BUG #7873: pg_restore --clean tries to drop tables that don't exist

Started by Nonamealmost 13 years ago83 messages
#1Noname
autarch@urth.org

The following bug has been logged on the website:

Bug reference: 7873
Logged by: Dave Rolsky
Email address: autarch@urth.org
PostgreSQL version: 9.2.3
Operating system: Linux
Description:

When you pass the --clean option to pg_restore it tries to drop tables
without checking if they exist. This results in lots of error output. If
you're running pg_restore via an automated process it's very hard to
distinguish between these "ok" errors and real errors.

It should be using "DROP TABLE IF EXISTS" and the equivalent for
constraints.

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#2Bruce Momjian
bruce@momjian.us
In reply to: Noname (#1)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Wed, Feb 13, 2013 at 08:22:43PM +0000, autarch@urth.org wrote:

The following bug has been logged on the website:

Bug reference: 7873
Logged by: Dave Rolsky
Email address: autarch@urth.org
PostgreSQL version: 9.2.3
Operating system: Linux
Description:

When you pass the --clean option to pg_restore it tries to drop tables
without checking if they exist. This results in lots of error output. If
you're running pg_restore via an automated process it's very hard to
distinguish between these "ok" errors and real errors.

It should be using "DROP TABLE IF EXISTS" and the equivalent for
constraints.

Well, I think the question is whether you want error feedback for things
that don't exist. I don't really know the answer.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#3Dave Rolsky
autarch@urth.org
In reply to: Bruce Momjian (#2)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Fri, 15 Feb 2013, Bruce Momjian wrote:

On Wed, Feb 13, 2013 at 08:22:43PM +0000, autarch@urth.org wrote:

The following bug has been logged on the website:

Bug reference: 7873
Logged by: Dave Rolsky
Email address: autarch@urth.org
PostgreSQL version: 9.2.3
Operating system: Linux
Description:

When you pass the --clean option to pg_restore it tries to drop tables
without checking if they exist. This results in lots of error output. If
you're running pg_restore via an automated process it's very hard to
distinguish between these "ok" errors and real errors.

It should be using "DROP TABLE IF EXISTS" and the equivalent for
constraints.

Well, I think the question is whether you want error feedback for things
that don't exist. I don't really know the answer.

Fair enough. It should probably an option to add "if exists", at least. I
can't imagine I'm the only using this tool to ship database updates around
to different machines, some of which may not have new tables. I'd really
like to be able to know when the restore fails versus when it succeeds but
is noisy.

Cheers,

-dave

/*============================================================
http://VegGuide.org http://blog.urth.org
Your guide to all that's veg House Absolute(ly Pointless)
============================================================*/

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#4Bruce Momjian
bruce@momjian.us
In reply to: Dave Rolsky (#3)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Fri, Feb 15, 2013 at 04:06:12PM -0600, Dave Rolsky wrote:

On Fri, 15 Feb 2013, Bruce Momjian wrote:

On Wed, Feb 13, 2013 at 08:22:43PM +0000, autarch@urth.org wrote:

The following bug has been logged on the website:

Bug reference: 7873
Logged by: Dave Rolsky
Email address: autarch@urth.org
PostgreSQL version: 9.2.3
Operating system: Linux
Description:

When you pass the --clean option to pg_restore it tries to drop tables
without checking if they exist. This results in lots of error output. If
you're running pg_restore via an automated process it's very hard to
distinguish between these "ok" errors and real errors.

It should be using "DROP TABLE IF EXISTS" and the equivalent for
constraints.

Well, I think the question is whether you want error feedback for things
that don't exist. I don't really know the answer.

Fair enough. It should probably an option to add "if exists", at
least. I can't imagine I'm the only using this tool to ship database
updates around to different machines, some of which may not have new
tables. I'd really like to be able to know when the restore fails
versus when it succeeds but is noisy.

All I can say is I don't remember anyone asking for this in the past.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#4)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

Bruce Momjian <bruce@momjian.us> writes:

On Fri, Feb 15, 2013 at 04:06:12PM -0600, Dave Rolsky wrote:

Fair enough. It should probably an option to add "if exists", at
least. I can't imagine I'm the only using this tool to ship database
updates around to different machines, some of which may not have new
tables. I'd really like to be able to know when the restore fails
versus when it succeeds but is noisy.

All I can say is I don't remember anyone asking for this in the past.

I think it has come up before. I wouldn't object to a pg_dump option to
add IF EXISTS to all the drop commands (though changing the default
behavior would be more controversial). Don't intend to spend my own
time on it though ...

regards, tom lane

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#6Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#5)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/2/16 Tom Lane <tgl@sss.pgh.pa.us>:

Bruce Momjian <bruce@momjian.us> writes:

On Fri, Feb 15, 2013 at 04:06:12PM -0600, Dave Rolsky wrote:

Fair enough. It should probably an option to add "if exists", at
least. I can't imagine I'm the only using this tool to ship database
updates around to different machines, some of which may not have new
tables. I'd really like to be able to know when the restore fails
versus when it succeeds but is noisy.

All I can say is I don't remember anyone asking for this in the past.

I think it has come up before. I wouldn't object to a pg_dump option to
add IF EXISTS to all the drop commands (though changing the default
behavior would be more controversial). Don't intend to spend my own
time on it though ...

we use this feature more than one year.

I'll send patch at Monday

Regards

Pavel Stehule

regards, tom lane

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#7Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#6)
1 attachment(s)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/2/16 Pavel Stehule <pavel.stehule@gmail.com>:

2013/2/16 Tom Lane <tgl@sss.pgh.pa.us>:

Bruce Momjian <bruce@momjian.us> writes:

On Fri, Feb 15, 2013 at 04:06:12PM -0600, Dave Rolsky wrote:

Fair enough. It should probably an option to add "if exists", at
least. I can't imagine I'm the only using this tool to ship database
updates around to different machines, some of which may not have new
tables. I'd really like to be able to know when the restore fails
versus when it succeeds but is noisy.

All I can say is I don't remember anyone asking for this in the past.

I think it has come up before. I wouldn't object to a pg_dump option to
add IF EXISTS to all the drop commands (though changing the default
behavior would be more controversial). Don't intend to spend my own
time on it though ...

we use this feature more than one year.

I'll send patch at Monday

here is patch, that we use about one year - originally for 9.1 - I did
port to 9.3

Regards

Pavel

Show quoted text

Regards

Pavel Stehule

regards, tom lane

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

Attachments:

conditional-drops.patchapplication/octet-stream; name=conditional-drops.patchDownload
*** a/doc/src/sgml/ref/pg_dump.sgml
--- b/doc/src/sgml/ref/pg_dump.sgml
***************
*** 592,597 **** PostgreSQL documentation
--- 592,607 ----
       </varlistentry>
  
       <varlistentry>
+       <term><option>--conditional-drops</option></term>
+       <listitem>
+        <para>
+         It use conditional commands (with <literal>IF EXISTS</literal>
+         clause) for cleaning database schema.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><option>--disable-dollar-quoting</></term>
        <listitem>
         <para>
*** a/doc/src/sgml/ref/pg_dumpall.sgml
--- b/doc/src/sgml/ref/pg_dumpall.sgml
***************
*** 270,275 **** PostgreSQL documentation
--- 270,285 ----
       </varlistentry>
  
       <varlistentry>
+       <term><option>--conditional-drops</option></term>
+       <listitem>
+        <para>
+         It use conditional commands (with <literal>IF EXISTS</literal>
+         clause) for cleaning database schema.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><option>--disable-dollar-quoting</></term>
        <listitem>
         <para>
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 137,142 **** static int	column_inserts = 0;
--- 137,143 ----
  static int	no_security_labels = 0;
  static int	no_unlogged_table_data = 0;
  static int	serializable_deferrable = 0;
+ static int	conditional_drops = 0;
  
  
  static void help(const char *progname);
***************
*** 338,343 **** main(int argc, char **argv)
--- 339,345 ----
  		{"attribute-inserts", no_argument, &column_inserts, 1},
  		{"binary-upgrade", no_argument, &binary_upgrade, 1},
  		{"column-inserts", no_argument, &column_inserts, 1},
+ 		{"conditional-drops", no_argument, &conditional_drops, 1},
  		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
  		{"disable-triggers", no_argument, &disable_triggers, 1},
  		{"exclude-table-data", required_argument, NULL, 4},
***************
*** 857,862 **** help(const char *progname)
--- 859,865 ----
  	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
  	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
  	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
+ 	printf(_("  --conditional-drops          use conditional drop commands for cleaning\n"));
  	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
  	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
  	printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
***************
*** 1987,1993 **** dumpDatabase(Archive *fout)
  
  	}
  
! 	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
  					  fmtId(datname));
  
  	dbDumpId = createDumpId();
--- 1990,1997 ----
  
  	}
  
! 	appendPQExpBuffer(delQry, "DROP DATABASE %s%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(datname));
  
  	dbDumpId = createDumpId();
***************
*** 7431,7437 **** dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
  
  	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
  
  	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
  
--- 7435,7443 ----
  
  	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP SCHEMA %s%s;\n",
! 						    conditional_drops ? "IF EXISTS " : "",
! 						    qnspname);
  
  	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
  
***************
*** 7490,7496 **** dumpExtension(Archive *fout, ExtensionInfo *extinfo)
  
  	qextname = pg_strdup(fmtId(extinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
  
  	if (!binary_upgrade)
  	{
--- 7496,7504 ----
  
  	qextname = pg_strdup(fmtId(extinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP EXTENSION %s%s;\n",
! 						    conditional_drops ? "IF EXISTS " : "",
! 						    qextname);
  
  	if (!binary_upgrade)
  	{
***************
*** 7664,7670 **** dumpEnumType(Archive *fout, TypeInfo *tyinfo)
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 7672,7679 ----
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 7794,7800 **** dumpRangeType(Archive *fout, TypeInfo *tyinfo)
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 7803,7810 ----
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 8134,8140 **** dumpBaseType(Archive *fout, TypeInfo *tyinfo)
  	 * the type and its I/O functions makes it impossible to drop the type any
  	 * other way.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s CASCADE;\n",
  					  qtypname);
--- 8144,8151 ----
  	 * the type and its I/O functions makes it impossible to drop the type any
  	 * other way.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s CASCADE;\n",
  					  qtypname);
***************
*** 8394,8400 **** dumpDomain(Archive *fout, TypeInfo *tyinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP DOMAIN %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 8405,8412 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP DOMAIN %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 8609,8615 **** dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 8621,8628 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 8920,8926 **** dumpProcLang(Archive *fout, ProcLangInfo *plang)
  	else
  		lanschema = NULL;
  
! 	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
  					  qlanname);
  
  	if (useParams)
--- 8933,8940 ----
  	else
  		lanschema = NULL;
  
! 	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  qlanname);
  
  	if (useParams)
***************
*** 9461,9467 **** dumpFunc(Archive *fout, FuncInfo *finfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
  					  fmtId(finfo->dobj.namespace->dobj.name),
  					  funcsig);
  
--- 9475,9482 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP FUNCTION %s%s.%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(finfo->dobj.namespace->dobj.name),
  					  funcsig);
  
***************
*** 9679,9685 **** dumpCast(Archive *fout, CastInfo *cast)
  	delqry = createPQExpBuffer();
  	labelq = createPQExpBuffer();
  
! 	appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
  					getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  				   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  
--- 9694,9701 ----
  	delqry = createPQExpBuffer();
  	labelq = createPQExpBuffer();
  
! 	appendPQExpBuffer(delqry, "DROP CAST %s(%s AS %s);\n",
! 					conditional_drops ? "IF EXISTS " : "",
  					getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  				   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  
***************
*** 9949,9955 **** dumpOpr(Archive *fout, OprInfo *oprinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
  					  fmtId(oprinfo->dobj.namespace->dobj.name),
  					  oprid->data);
  
--- 9965,9972 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR %s%s.%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(oprinfo->dobj.namespace->dobj.name),
  					  oprid->data);
  
***************
*** 10235,10241 **** dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
  					  fmtId(opcinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opcinfo->dobj.name));
--- 10252,10259 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(opcinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opcinfo->dobj.name));
***************
*** 10679,10685 **** dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
  					  fmtId(opfinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opfinfo->dobj.name));
--- 10697,10704 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(opfinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opfinfo->dobj.name));
***************
*** 10853,10859 **** dumpCollation(Archive *fout, CollInfo *collinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP COLLATION %s",
  					  fmtId(collinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(collinfo->dobj.name));
--- 10872,10879 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP COLLATION %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(collinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(collinfo->dobj.name));
***************
*** 10950,10956 **** dumpConversion(Archive *fout, ConvInfo *convinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP CONVERSION %s",
  					  fmtId(convinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(convinfo->dobj.name));
--- 10970,10977 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP CONVERSION %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(convinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(convinfo->dobj.name));
***************
*** 11194,11200 **** dumpAgg(Archive *fout, AggInfo *agginfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
  					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
  					  aggsig);
  
--- 11215,11222 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP AGGREGATE %s%s.%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
  					  aggsig);
  
***************
*** 11293,11299 **** dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
  					  fmtId(prsinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(prsinfo->dobj.name));
--- 11315,11322 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(prsinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(prsinfo->dobj.name));
***************
*** 11380,11386 **** dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
  					  fmtId(dictinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(dictinfo->dobj.name));
--- 11403,11410 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(dictinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(dictinfo->dobj.name));
***************
*** 11446,11452 **** dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
  					  fmtId(tmplinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(tmplinfo->dobj.name));
--- 11470,11477 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tmplinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(tmplinfo->dobj.name));
***************
*** 11574,11580 **** dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
  					  fmtId(cfginfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(cfginfo->dobj.name));
--- 11599,11606 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s%s",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(cfginfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(cfginfo->dobj.name));
***************
*** 11650,11656 **** dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
  					  qfdwname);
  
  	appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
--- 11676,11683 ----
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  qfdwname);
  
  	appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
***************
*** 11743,11749 **** dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP SERVER %s;\n",
  					  qsrvname);
  
  	appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
--- 11770,11777 ----
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP SERVER %s%s;\n",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  qsrvname);
  
  	appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
***************
*** 11861,11867 **** dumpUserMappings(Archive *fout,
  		appendPQExpBuffer(q, ";\n");
  
  		resetPQExpBuffer(delq);
! 		appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
  		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
  
  		resetPQExpBuffer(tag);
--- 11889,11897 ----
  		appendPQExpBuffer(q, ";\n");
  
  		resetPQExpBuffer(delq);
! 		appendPQExpBuffer(delq, "DROP USER MAPPING %sFOR %s",
! 							    conditional_drops ? "IF EXISTS " : "",
! 							    fmtId(usename));
  		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
  
  		resetPQExpBuffer(tag);
***************
*** 12448,12454 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP VIEW %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
--- 12478,12485 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP VIEW %s%s.",
! 						  conditional_drops ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
***************
*** 12510,12516 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
--- 12541,12548 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP %s %s%s.", reltypename,
! 						  conditional_drops ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
***************
*** 13002,13008 **** dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "ALTER TABLE %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s ",
  					  fmtId(tbinfo->dobj.name));
--- 13034,13041 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "ALTER TABLE %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s ",
  					  fmtId(tbinfo->dobj.name));
***************
*** 13106,13112 **** dumpIndex(Archive *fout, IndxInfo *indxinfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP INDEX %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(indxinfo->dobj.name));
--- 13139,13146 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP INDEX %s%s.",
! 						  conditional_drops ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(indxinfo->dobj.name));
***************
*** 13225,13231 **** dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
--- 13259,13266 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE %sONLY %s.",
! 						  conditional_drops ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
***************
*** 13258,13264 **** dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
--- 13293,13300 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE %sONLY %s.",
! 						  conditional_drops ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
***************
*** 13527,13533 **** dumpSequence(Archive *fout, TableInfo *tbinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delqry, "%s;\n",
  					  fmtId(tbinfo->dobj.name));
--- 13563,13570 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP SEQUENCE %s%s.",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delqry, "%s;\n",
  					  fmtId(tbinfo->dobj.name));
***************
*** 13715,13721 **** dumpTrigger(Archive *fout, TriggerInfo *tginfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
  					  fmtId(tginfo->dobj.name));
  	appendPQExpBuffer(delqry, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
--- 13752,13759 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP TRIGGER %s%s ",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(tginfo->dobj.name));
  	appendPQExpBuffer(delqry, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
***************
*** 14055,14061 **** dumpRule(Archive *fout, RuleInfo *rinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delcmd, "DROP RULE %s ",
  					  fmtId(rinfo->dobj.name));
  	appendPQExpBuffer(delcmd, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
--- 14093,14100 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delcmd, "DROP RULE %s%s ",
! 					  conditional_drops ? "IF EXISTS " : "",
  					  fmtId(rinfo->dobj.name));
  	appendPQExpBuffer(delcmd, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
*** a/src/bin/pg_dump/pg_dumpall.c
--- b/src/bin/pg_dump/pg_dumpall.c
***************
*** 67,72 **** static bool verbose = false;
--- 67,73 ----
  
  static int	binary_upgrade = 0;
  static int	column_inserts = 0;
+ static int	conditional_drops = 0;
  static int	disable_dollar_quoting = 0;
  static int	disable_triggers = 0;
  static int	inserts = 0;
***************
*** 111,116 **** main(int argc, char *argv[])
--- 112,118 ----
  		{"attribute-inserts", no_argument, &column_inserts, 1},
  		{"binary-upgrade", no_argument, &binary_upgrade, 1},
  		{"column-inserts", no_argument, &column_inserts, 1},
+ 		{"conditional-drops", no_argument, &conditional_drops, 1},
  		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
  		{"disable-triggers", no_argument, &disable_triggers, 1},
  		{"inserts", no_argument, &inserts, 1},
***************
*** 344,349 **** main(int argc, char *argv[])
--- 346,353 ----
  		appendPQExpBuffer(pgdumpopts, " --binary-upgrade");
  	if (column_inserts)
  		appendPQExpBuffer(pgdumpopts, " --column-inserts");
+ 	if (conditional_drops)
+ 		appendPQExpBuffer(pgdumpopts, " --conditional-drops");
  	if (disable_dollar_quoting)
  		appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting");
  	if (disable_triggers)
***************
*** 555,560 **** help(void)
--- 559,565 ----
  	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
  	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
  	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
+ 	printf(_("  --conditional-drops          use conditional drops command for cleaning\n"));
  	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
  	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
  	printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
#8Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#7)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Tue, Feb 19, 2013 at 6:00 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/2/16 Pavel Stehule <pavel.stehule@gmail.com>:

2013/2/16 Tom Lane <tgl@sss.pgh.pa.us>:

I think it has come up before. I wouldn't object to a pg_dump option to
add IF EXISTS to all the drop commands (though changing the default
behavior would be more controversial). Don't intend to spend my own
time on it though ...

FYI, it was proposed here:
/messages/by-id/507AD08C.5020603@dalibo.com

here is patch, that we use about one year - originally for 9.1 - I did
port to 9.3

dropdb and dropuser both support a similar option named --if-exists. I
suggest --if-exists instead of --conditional-drops for consistency.
I've only glanced at the patch, but if it makes no sense to use
--conditional-drops (or --if-exists, whatever it ends up being called)
without --clean, then attempting to do so should raise an error.

Josh

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#9Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#8)
1 attachment(s)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/2/21 Josh Kupershmidt <schmiddy@gmail.com>:

On Tue, Feb 19, 2013 at 6:00 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/2/16 Pavel Stehule <pavel.stehule@gmail.com>:

2013/2/16 Tom Lane <tgl@sss.pgh.pa.us>:

I think it has come up before. I wouldn't object to a pg_dump option to
add IF EXISTS to all the drop commands (though changing the default
behavior would be more controversial). Don't intend to spend my own
time on it though ...

FYI, it was proposed here:
/messages/by-id/507AD08C.5020603@dalibo.com

here is patch, that we use about one year - originally for 9.1 - I did
port to 9.3

dropdb and dropuser both support a similar option named --if-exists. I
suggest --if-exists instead of --conditional-drops for consistency.
I've only glanced at the patch, but if it makes no sense to use
--conditional-drops (or --if-exists, whatever it ends up being called)
without --clean, then attempting to do so should raise an error.

so

* --conditional-drops replaced by --if-exists
* -- additional check, available only with -c option
* fix bug with dump custom functions

Regards

Pavel

Show quoted text

Josh

Attachments:

conditional-drops.patchapplication/octet-stream; name=conditional-drops.patchDownload
*** a/doc/src/sgml/ref/pg_dump.sgml
--- b/doc/src/sgml/ref/pg_dump.sgml
***************
*** 592,597 **** PostgreSQL documentation
--- 592,607 ----
       </varlistentry>
  
       <varlistentry>
+       <term><option>--if-exists</option></term>
+       <listitem>
+        <para>
+         It use conditional commands (with <literal>IF EXISTS</literal>
+         clause) for cleaning database schema.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><option>--disable-dollar-quoting</></term>
        <listitem>
         <para>
*** a/doc/src/sgml/ref/pg_dumpall.sgml
--- b/doc/src/sgml/ref/pg_dumpall.sgml
***************
*** 270,275 **** PostgreSQL documentation
--- 270,285 ----
       </varlistentry>
  
       <varlistentry>
+       <term><option>--if-exists</option></term>
+       <listitem>
+        <para>
+         It use conditional commands (with <literal>IF EXISTS</literal>
+         clause) for cleaning database schema.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><option>--disable-dollar-quoting</></term>
        <listitem>
         <para>
*** a/src/bin/pg_dump/pg_backup.h
--- b/src/bin/pg_dump/pg_backup.h
***************
*** 108,113 **** typedef struct _restoreOptions
--- 108,114 ----
  	char	   *superuser;		/* Username to use as superuser */
  	char	   *use_role;		/* Issue SET ROLE to this */
  	int			dropSchema;
+ 	int			if_exists;
  	const char *filename;
  	int			dataOnly;
  	int			schemaOnly;
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
***************
*** 118,125 **** static const char *modulename = gettext_noop("archiver");
  static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
  		 const int compression, ArchiveMode mode);
  static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
! 					  ArchiveHandle *AH);
! static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
  static char *replace_line_endings(const char *str);
  static void _doSetFixedOutputState(ArchiveHandle *AH);
  static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
--- 118,126 ----
  static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
  		 const int compression, ArchiveMode mode);
  static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
! 					  ArchiveHandle *AH, bool if_exists);
! static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt,
! 								 bool isData, bool acl_pass);
  static char *replace_line_endings(const char *str);
  static void _doSetFixedOutputState(ArchiveHandle *AH);
  static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
***************
*** 296,301 **** RestoreArchive(Archive *AHX)
--- 297,303 ----
  	bool		parallel_mode;
  	TocEntry   *te;
  	OutputContext sav;
+ 	
  
  	AH->stage = STAGE_INITIALIZING;
  
***************
*** 2903,2909 **** _selectTablespace(ArchiveHandle *AH, const char *tablespace)
   * information used is all that's available in older dump files.
   */
  static void
! _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
  {
  	const char *type = te->desc;
  
--- 2905,2911 ----
   * information used is all that's available in older dump files.
   */
  static void
! _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH, bool if_exists)
  {
  	const char *type = te->desc;
  
***************
*** 2969,2977 **** _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
  		strcmp(type, "OPERATOR CLASS") == 0 ||
  		strcmp(type, "OPERATOR FAMILY") == 0)
  	{
! 		/* Chop "DROP " off the front and make a modifiable copy */
! 		char	   *first = pg_strdup(te->dropStmt + 5);
! 		char	   *last;
  
  		/* point to last character in string */
  		last = first + strlen(first) - 1;
--- 2971,3006 ----
  		strcmp(type, "OPERATOR CLASS") == 0 ||
  		strcmp(type, "OPERATOR FAMILY") == 0)
  	{
! 		char	    *first;
! 		char	    *last;
! 
! 		if (!if_exists)
! 		{
! 			/* just chop first 5 chars - "DROP", and create a modifiable copy */
! 			first = pg_strdup(te->dropStmt + 5);
! 		}
! 		else
! 		{
! 			char buffer[40];
! 			size_t   l;
! 
! 			/* IF EXISTS clause should be optional, check it*/
! 			snprintf(buffer, sizeof(buffer), "DROP %s%s", type,
! 								if_exists ? " IF EXISTS" : "");
! 			l = strlen(buffer);
! 
! 			if (strncmp(te->dropStmt, buffer, l) == 0)
! 			{
! 				/* append command type to target type */
! 				appendPQExpBufferStr(buf, type);
! 
! 				/* skip first n chars, and create a modifieble copy */
! 				first = pg_strdup(te->dropStmt + l);
! 			}
! 			else
! 				/* IF EXISTS clause was not used, simple solution */
! 				first = pg_strdup(te->dropStmt + 5);
! 		}
  
  		/* point to last character in string */
  		last = first + strlen(first) - 1;
***************
*** 2992,2999 **** _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
  }
  
  static void
! _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
  {
  	/* ACLs are dumped only during acl pass */
  	if (acl_pass)
  	{
--- 3021,3031 ----
  }
  
  static void
! _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData,
! 								      bool acl_pass)
  {
+ 	int		 if_exists = ropt->if_exists;
+ 
  	/* ACLs are dumped only during acl pass */
  	if (acl_pass)
  	{
***************
*** 3150,3156 **** _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
  			PQExpBuffer temp = createPQExpBuffer();
  
  			appendPQExpBuffer(temp, "ALTER ");
! 			_getObjectDescription(temp, te, AH);
  			appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner));
  			ahprintf(AH, "%s\n\n", temp->data);
  			destroyPQExpBuffer(temp);
--- 3182,3188 ----
  			PQExpBuffer temp = createPQExpBuffer();
  
  			appendPQExpBuffer(temp, "ALTER ");
! 			_getObjectDescription(temp, te, AH, if_exists);
  			appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner));
  			ahprintf(AH, "%s\n\n", temp->data);
  			destroyPQExpBuffer(temp);
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 137,142 **** static int	column_inserts = 0;
--- 137,143 ----
  static int	no_security_labels = 0;
  static int	no_unlogged_table_data = 0;
  static int	serializable_deferrable = 0;
+ static int	if_exists = 0;
  
  
  static void help(const char *progname);
***************
*** 338,343 **** main(int argc, char **argv)
--- 339,345 ----
  		{"attribute-inserts", no_argument, &column_inserts, 1},
  		{"binary-upgrade", no_argument, &binary_upgrade, 1},
  		{"column-inserts", no_argument, &column_inserts, 1},
+ 		{"if-exists", no_argument, &if_exists, 1},
  		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
  		{"disable-triggers", no_argument, &disable_triggers, 1},
  		{"exclude-table-data", required_argument, NULL, 4},
***************
*** 551,556 **** main(int argc, char **argv)
--- 553,561 ----
  		exit_nicely(1);
  	}
  
+ 	if (if_exists && !outputClean)
+ 		exit_horribly(NULL, "option --if-exists requires -c/--clean option\n");
+ 
  	/* Identify archive format to emit */
  	archiveFormat = parseArchiveFormat(format, &archiveMode);
  
***************
*** 780,785 **** main(int argc, char **argv)
--- 785,791 ----
  	ropt->dropSchema = outputClean;
  	ropt->dataOnly = dataOnly;
  	ropt->schemaOnly = schemaOnly;
+ 	ropt->if_exists = if_exists;
  	ropt->dumpSections = dumpSections;
  	ropt->aclsSkip = aclsSkip;
  	ropt->superuser = outputSuperuser;
***************
*** 857,862 **** help(const char *progname)
--- 863,869 ----
  	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
  	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
  	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
+ 	printf(_("  --if-exists                  don't report error if cleaned object doesn't exist\n"));
  	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
  	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
  	printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
***************
*** 1987,1993 **** dumpDatabase(Archive *fout)
  
  	}
  
! 	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
  					  fmtId(datname));
  
  	dbDumpId = createDumpId();
--- 1994,2001 ----
  
  	}
  
! 	appendPQExpBuffer(delQry, "DROP DATABASE %s%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(datname));
  
  	dbDumpId = createDumpId();
***************
*** 7431,7437 **** dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
  
  	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
  
  	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
  
--- 7439,7447 ----
  
  	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP SCHEMA %s%s;\n",
! 						    if_exists ? "IF EXISTS " : "",
! 						    qnspname);
  
  	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
  
***************
*** 7490,7496 **** dumpExtension(Archive *fout, ExtensionInfo *extinfo)
  
  	qextname = pg_strdup(fmtId(extinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
  
  	if (!binary_upgrade)
  	{
--- 7500,7508 ----
  
  	qextname = pg_strdup(fmtId(extinfo->dobj.name));
  
! 	appendPQExpBuffer(delq, "DROP EXTENSION %s%s;\n",
! 						    if_exists ? "IF EXISTS " : "",
! 						    qextname);
  
  	if (!binary_upgrade)
  	{
***************
*** 7664,7670 **** dumpEnumType(Archive *fout, TypeInfo *tyinfo)
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 7676,7683 ----
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 7794,7800 **** dumpRangeType(Archive *fout, TypeInfo *tyinfo)
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 7807,7814 ----
  	 * CASCADE shouldn't be required here as for normal types since the I/O
  	 * functions are generic and do not get dropped.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 8134,8140 **** dumpBaseType(Archive *fout, TypeInfo *tyinfo)
  	 * the type and its I/O functions makes it impossible to drop the type any
  	 * other way.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s CASCADE;\n",
  					  qtypname);
--- 8148,8155 ----
  	 * the type and its I/O functions makes it impossible to drop the type any
  	 * other way.
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s CASCADE;\n",
  					  qtypname);
***************
*** 8394,8400 **** dumpDomain(Archive *fout, TypeInfo *tyinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP DOMAIN %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 8409,8416 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP DOMAIN %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 8609,8615 **** dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s.",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
--- 8625,8632 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tyinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s;\n",
  					  qtypname);
***************
*** 8920,8926 **** dumpProcLang(Archive *fout, ProcLangInfo *plang)
  	else
  		lanschema = NULL;
  
! 	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
  					  qlanname);
  
  	if (useParams)
--- 8937,8944 ----
  	else
  		lanschema = NULL;
  
! 	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  qlanname);
  
  	if (useParams)
***************
*** 9461,9467 **** dumpFunc(Archive *fout, FuncInfo *finfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
  					  fmtId(finfo->dobj.namespace->dobj.name),
  					  funcsig);
  
--- 9479,9486 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP FUNCTION %s%s.%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(finfo->dobj.namespace->dobj.name),
  					  funcsig);
  
***************
*** 9679,9685 **** dumpCast(Archive *fout, CastInfo *cast)
  	delqry = createPQExpBuffer();
  	labelq = createPQExpBuffer();
  
! 	appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
  					getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  				   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  
--- 9698,9705 ----
  	delqry = createPQExpBuffer();
  	labelq = createPQExpBuffer();
  
! 	appendPQExpBuffer(delqry, "DROP CAST %s(%s AS %s);\n",
! 					if_exists ? "IF EXISTS " : "",
  					getFormattedTypeName(fout, cast->castsource, zeroAsNone),
  				   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
  
***************
*** 9949,9955 **** dumpOpr(Archive *fout, OprInfo *oprinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
  					  fmtId(oprinfo->dobj.namespace->dobj.name),
  					  oprid->data);
  
--- 9969,9976 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR %s%s.%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(oprinfo->dobj.namespace->dobj.name),
  					  oprid->data);
  
***************
*** 10235,10241 **** dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
  					  fmtId(opcinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opcinfo->dobj.name));
--- 10256,10263 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(opcinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opcinfo->dobj.name));
***************
*** 10679,10685 **** dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
  					  fmtId(opfinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opfinfo->dobj.name));
--- 10701,10708 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(opfinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s",
  					  fmtId(opfinfo->dobj.name));
***************
*** 10853,10859 **** dumpCollation(Archive *fout, CollInfo *collinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP COLLATION %s",
  					  fmtId(collinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(collinfo->dobj.name));
--- 10876,10883 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP COLLATION %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(collinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(collinfo->dobj.name));
***************
*** 10950,10956 **** dumpConversion(Archive *fout, ConvInfo *convinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP CONVERSION %s",
  					  fmtId(convinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(convinfo->dobj.name));
--- 10974,10981 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP CONVERSION %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(convinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(convinfo->dobj.name));
***************
*** 11194,11200 **** dumpAgg(Archive *fout, AggInfo *agginfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
  					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
  					  aggsig);
  
--- 11219,11226 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP AGGREGATE %s%s.%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
  					  aggsig);
  
***************
*** 11293,11299 **** dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
  					  fmtId(prsinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(prsinfo->dobj.name));
--- 11319,11326 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(prsinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(prsinfo->dobj.name));
***************
*** 11380,11386 **** dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
  					  fmtId(dictinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(dictinfo->dobj.name));
--- 11407,11414 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(dictinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(dictinfo->dobj.name));
***************
*** 11446,11452 **** dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
  					  fmtId(tmplinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(tmplinfo->dobj.name));
--- 11474,11481 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tmplinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(tmplinfo->dobj.name));
***************
*** 11574,11580 **** dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
  					  fmtId(cfginfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(cfginfo->dobj.name));
--- 11603,11610 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s%s",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(cfginfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, ".%s;\n",
  					  fmtId(cfginfo->dobj.name));
***************
*** 11650,11656 **** dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
  					  qfdwname);
  
  	appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
--- 11680,11687 ----
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  qfdwname);
  
  	appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
***************
*** 11743,11749 **** dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP SERVER %s;\n",
  					  qsrvname);
  
  	appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
--- 11774,11781 ----
  
  	appendPQExpBuffer(q, ";\n");
  
! 	appendPQExpBuffer(delq, "DROP SERVER %s%s;\n",
! 					  if_exists ? "IF EXISTS " : "",
  					  qsrvname);
  
  	appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
***************
*** 11861,11867 **** dumpUserMappings(Archive *fout,
  		appendPQExpBuffer(q, ";\n");
  
  		resetPQExpBuffer(delq);
! 		appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
  		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
  
  		resetPQExpBuffer(tag);
--- 11893,11901 ----
  		appendPQExpBuffer(q, ";\n");
  
  		resetPQExpBuffer(delq);
! 		appendPQExpBuffer(delq, "DROP USER MAPPING %sFOR %s",
! 							    if_exists ? "IF EXISTS " : "",
! 							    fmtId(usename));
  		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
  
  		resetPQExpBuffer(tag);
***************
*** 12448,12454 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP VIEW %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
--- 12482,12489 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP VIEW %s%s.",
! 						  if_exists ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
***************
*** 12510,12516 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
--- 12545,12552 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP %s %s%s.", reltypename,
! 						  if_exists ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(tbinfo->dobj.name));
***************
*** 13002,13008 **** dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "ALTER TABLE %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s ",
  					  fmtId(tbinfo->dobj.name));
--- 13038,13045 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delq, "ALTER TABLE %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delq, "%s ",
  					  fmtId(tbinfo->dobj.name));
***************
*** 13106,13112 **** dumpIndex(Archive *fout, IndxInfo *indxinfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP INDEX %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(indxinfo->dobj.name));
--- 13143,13150 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "DROP INDEX %s%s.",
! 						  if_exists ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s;\n",
  						  fmtId(indxinfo->dobj.name));
***************
*** 13225,13231 **** dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
--- 13263,13270 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE %sONLY %s.",
! 						  if_exists ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
***************
*** 13258,13264 **** dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
--- 13297,13304 ----
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
  		 */
! 		appendPQExpBuffer(delq, "ALTER TABLE %sONLY %s.",
! 						  if_exists ? "IF EXISTS " : "",
  						  fmtId(tbinfo->dobj.namespace->dobj.name));
  		appendPQExpBuffer(delq, "%s ",
  						  fmtId(tbinfo->dobj.name));
***************
*** 13527,13533 **** dumpSequence(Archive *fout, TableInfo *tbinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delqry, "%s;\n",
  					  fmtId(tbinfo->dobj.name));
--- 13567,13574 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP SEQUENCE %s%s.",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
  	appendPQExpBuffer(delqry, "%s;\n",
  					  fmtId(tbinfo->dobj.name));
***************
*** 13715,13721 **** dumpTrigger(Archive *fout, TriggerInfo *tginfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
  					  fmtId(tginfo->dobj.name));
  	appendPQExpBuffer(delqry, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
--- 13756,13763 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delqry, "DROP TRIGGER %s%s ",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(tginfo->dobj.name));
  	appendPQExpBuffer(delqry, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
***************
*** 14055,14061 **** dumpRule(Archive *fout, RuleInfo *rinfo)
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delcmd, "DROP RULE %s ",
  					  fmtId(rinfo->dobj.name));
  	appendPQExpBuffer(delcmd, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
--- 14097,14104 ----
  	/*
  	 * DROP must be fully qualified in case same name appears in pg_catalog
  	 */
! 	appendPQExpBuffer(delcmd, "DROP RULE %s%s ",
! 					  if_exists ? "IF EXISTS " : "",
  					  fmtId(rinfo->dobj.name));
  	appendPQExpBuffer(delcmd, "ON %s.",
  					  fmtId(tbinfo->dobj.namespace->dobj.name));
*** a/src/bin/pg_dump/pg_dumpall.c
--- b/src/bin/pg_dump/pg_dumpall.c
***************
*** 68,73 **** static bool verbose = false;
--- 68,74 ----
  
  static int	binary_upgrade = 0;
  static int	column_inserts = 0;
+ static int	if_exists = 0;
  static int	disable_dollar_quoting = 0;
  static int	disable_triggers = 0;
  static int	inserts = 0;
***************
*** 112,117 **** main(int argc, char *argv[])
--- 113,119 ----
  		{"attribute-inserts", no_argument, &column_inserts, 1},
  		{"binary-upgrade", no_argument, &binary_upgrade, 1},
  		{"column-inserts", no_argument, &column_inserts, 1},
+ 		{"if-exists", no_argument, &if_exists, 1},
  		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
  		{"disable-triggers", no_argument, &disable_triggers, 1},
  		{"inserts", no_argument, &inserts, 1},
***************
*** 345,350 **** main(int argc, char *argv[])
--- 347,354 ----
  		appendPQExpBuffer(pgdumpopts, " --binary-upgrade");
  	if (column_inserts)
  		appendPQExpBuffer(pgdumpopts, " --column-inserts");
+ 	if (if_exists)
+ 		appendPQExpBuffer(pgdumpopts, " --if-exists");
  	if (disable_dollar_quoting)
  		appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting");
  	if (disable_triggers)
***************
*** 556,561 **** help(void)
--- 560,566 ----
  	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
  	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
  	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
+ 	printf(_("  --if-exists                  don't report error if cleaned object doesn't exist\n"));
  	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
  	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
  	printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
#10Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#9)
Re: BUG #7873: pg_restore --clean tries to drop tables that don't exist

[Moving to -hackers]

On Sat, Feb 23, 2013 at 2:51 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

so

* --conditional-drops replaced by --if-exists

Thanks for the fixes, I played around with the patch a bit. I was sort
of expecting this example to work (after setting up the regression
database with `make installcheck`)

pg_dump --clean --if-exists -Fp -d regression --file=regression.sql
createdb test
psql -v ON_ERROR_STOP=1 --single-transaction -d test -f regression.sql

But it fails, first at:
...
DROP TRIGGER IF EXISTS tsvectorupdate ON public.test_tsvector;
ERROR: relation "public.test_tsvector" does not exist

This seems like a shortcoming of DROP TRIGGER ... IF EXISTS, and it
looks like DROP RULE ... IF EXISTS has the same problem. I recall DROP
... IF EXISTS being fixed recently for not to error out if the schema
specified for the object does not exist, and ISTM the same arguments
could be made in favor of fixing DROP TRIGGER/TABLE ... IF EXISTS not
to error out if the table doesn't exist.

Working further through the dump of the regression database, these
also present problems for --clean --if-exists dumps:

DROP CAST IF EXISTS (text AS public.casttesttype);
ERROR: type "public.casttesttype" does not exist

DROP OPERATOR IF EXISTS public.<% (point, widget);
ERROR: type "widget" does not exist

DROP FUNCTION IF EXISTS public.pt_in_widget(point, widget);
ERROR: type "widget" does not exist

I'm not sure whether DROP CAST/OPERATOR/FUNCTION IF EXISTS should be
more tolerant of nonexistent types, of if the mess could perhaps be
avoided by dump reordering.

Note, this usability problem affects unpatched head as well:

pg_dump -Fc -d regression --file=regression.dump
pg_restore --clean -1 -d regression regression.dump
...
pg_restore: [archiver (db)] could not execute query: ERROR: type
"widget" does not exist
Command was: DROP FUNCTION public.widget_out(widget);

(The use here is a little different than the first example above, but
I would still expect this case to work.) The above problems with IF
EXISTS aren't really a problem of the patch per se, but IMO it would
be nice to straighten all the issues out together for 9.4.

* -- additional check, available only with -c option

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

Some comments on the changes:

1. There is at least one IF EXISTS check missing from pg_dump.c, see
for example this statement from a dump of the regression database with
--if-exists:

ALTER TABLE public.nv_child_2010 DROP CONSTRAINT nv_child_2010_d_check;

2. Shouldn't pg_restore get --if-exists as well?

3.
+ printf(_(" --if-exists don't report error if
cleaned object doesn't exist\n"));

This help output bleeds just over our de facto 80-character limit.
Also contractions seem to be avoided elsewhere. It's a little hard to
squeeze a decent explanation into one line, but perhaps:

Use IF EXISTS when dropping objects

would be better. The sgml changes could use some wordsmithing and
grammar fixes. I could clean these up for you in a later version if
you'd like.

4. There seem to be spurious whitespace changes to the function
prototype and declaration for _printTocEntry.

That's all I've had time for so far...

Josh

--
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

#11Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#10)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

[Moving to -hackers]

On Sat, Feb 23, 2013 at 2:51 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

so

* --conditional-drops replaced by --if-exists

Thanks for the fixes, I played around with the patch a bit. I was sort
of expecting this example to work (after setting up the regression
database with `make installcheck`)

pg_dump --clean --if-exists -Fp -d regression --file=regression.sql
createdb test
psql -v ON_ERROR_STOP=1 --single-transaction -d test -f regression.sql

But it fails, first at:
...
DROP TRIGGER IF EXISTS tsvectorupdate ON public.test_tsvector;
ERROR: relation "public.test_tsvector" does not exist

This seems like a shortcoming of DROP TRIGGER ... IF EXISTS, and it
looks like DROP RULE ... IF EXISTS has the same problem. I recall DROP
... IF EXISTS being fixed recently for not to error out if the schema
specified for the object does not exist, and ISTM the same arguments
could be made in favor of fixing DROP TRIGGER/TABLE ... IF EXISTS not
to error out if the table doesn't exist.

Working further through the dump of the regression database, these
also present problems for --clean --if-exists dumps:

DROP CAST IF EXISTS (text AS public.casttesttype);
ERROR: type "public.casttesttype" does not exist

DROP OPERATOR IF EXISTS public.<% (point, widget);
ERROR: type "widget" does not exist

DROP FUNCTION IF EXISTS public.pt_in_widget(point, widget);
ERROR: type "widget" does not exist

I'm not sure whether DROP CAST/OPERATOR/FUNCTION IF EXISTS should be
more tolerant of nonexistent types, of if the mess could perhaps be
avoided by dump reordering.

Note, this usability problem affects unpatched head as well:

pg_dump -Fc -d regression --file=regression.dump
pg_restore --clean -1 -d regression regression.dump
...
pg_restore: [archiver (db)] could not execute query: ERROR: type
"widget" does not exist
Command was: DROP FUNCTION public.widget_out(widget);

(The use here is a little different than the first example above, but
I would still expect this case to work.) The above problems with IF
EXISTS aren't really a problem of the patch per se, but IMO it would
be nice to straighten all the issues out together for 9.4.

ok

* -- additional check, available only with -c option

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

no

some people - like we in our company would to use this feature for
quiet and strict mode for plain text format too.

enabling this feature has zero overhead so there are no reason block
it anywhere.

Some comments on the changes:

1. There is at least one IF EXISTS check missing from pg_dump.c, see
for example this statement from a dump of the regression database with
--if-exists:

ALTER TABLE public.nv_child_2010 DROP CONSTRAINT nv_child_2010_d_check;

2. Shouldn't pg_restore get --if-exists as well?

3.
+ printf(_(" --if-exists don't report error if
cleaned object doesn't exist\n"));

This help output bleeds just over our de facto 80-character limit.
Also contractions seem to be avoided elsewhere. It's a little hard to
squeeze a decent explanation into one line, but perhaps:

Use IF EXISTS when dropping objects

would be better. The sgml changes could use some wordsmithing and
grammar fixes. I could clean these up for you in a later version if
you'd like.

4. There seem to be spurious whitespace changes to the function
prototype and declaration for _printTocEntry.

I'll send updated version in next months

Thank you for review

Regards

Pavel

That's all I've had time for so far...

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#11)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Fri, Mar 8, 2013 at 2:23 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

no

some people - like we in our company would to use this feature for
quiet and strict mode for plain text format too.

enabling this feature has zero overhead so there are no reason block
it anywhere.

I'm not sure I understand what you're getting at, but maybe my
proposal wasn't so clear. Right now, you can specify --clean along
with -Fc to pg_dump, and pg_dump will not complain even though this
combination is nonsense. I am proposing that pg_dump error out in this
case, i.e.

$ pg_dump -Fc --file=test.dump --clean -d test
pg_dump: option --clean only valid with plain format dump

Although this lack of an error a (IMO) misfeature of existing pg_dump,
so if you'd rather leave this issue aside for your patch, that is
fine.

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#12)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

On Fri, Mar 8, 2013 at 2:23 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

no

some people - like we in our company would to use this feature for
quiet and strict mode for plain text format too.

enabling this feature has zero overhead so there are no reason block
it anywhere.

I'm not sure I understand what you're getting at, but maybe my
proposal wasn't so clear. Right now, you can specify --clean along
with -Fc to pg_dump, and pg_dump will not complain even though this
combination is nonsense. I am proposing that pg_dump error out in this
case, i.e.

$ pg_dump -Fc --file=test.dump --clean -d test
pg_dump: option --clean only valid with plain format dump

Although this lack of an error a (IMO) misfeature of existing pg_dump,
so if you'd rather leave this issue aside for your patch, that is
fine.

I'll see - please, stay tuned to 9.4 first commitfest

Regards

Pavel

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#13)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Fri, Mar 8, 2013 at 11:58 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I'll see - please, stay tuned to 9.4 first commitfest

Hi Pavel,
Just a reminder, I didn't see this patch in the current commitfest. I
would be happy to spend some more time reviewing if you wish to pursue
the patch.

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#14)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/6/17 Josh Kupershmidt <schmiddy@gmail.com>:

On Fri, Mar 8, 2013 at 11:58 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I'll see - please, stay tuned to 9.4 first commitfest

Hi Pavel,
Just a reminder, I didn't see this patch in the current commitfest. I
would be happy to spend some more time reviewing if you wish to pursue
the patch.

Hello

yes, I hadn't free time for finalization of last patch. I hope so I
can do final version next month to next commitfest.

Regards and thank you

Pavel

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#12)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

On Fri, Mar 8, 2013 at 2:23 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

no

some people - like we in our company would to use this feature for
quiet and strict mode for plain text format too.

enabling this feature has zero overhead so there are no reason block
it anywhere.

I'm not sure I understand what you're getting at, but maybe my
proposal wasn't so clear. Right now, you can specify --clean along
with -Fc to pg_dump, and pg_dump will not complain even though this
combination is nonsense. I am proposing that pg_dump error out in this
case, i.e.

$ pg_dump -Fc --file=test.dump --clean -d test
pg_dump: option --clean only valid with plain format dump

Although this lack of an error a (IMO) misfeature of existing pg_dump,
so if you'd rather leave this issue aside for your patch, that is
fine.

I tested last patch and I am thinking so this patch has sense for
custom format too

[postgres@localhost ~]$ /usr/local/pgsql/bin/pg_dump --clean -t a
-Fc postgres > dump
[postgres@localhost ~]$ psql -c "drop table a"
DROP TABLE
[postgres@localhost ~]$ pg_restore --clean -d postgres dump
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 171; 1259 16462 TABLE
a postgres
pg_restore: [archiver (db)] could not execute query: ERROR: table "a"
does not exist
Command was: DROP TABLE public.a;

WARNING: errors ignored on restore: 1

[postgres@localhost ~]$ /usr/local/pgsql/bin/pg_dump --if-exist
--clean -t a -Fc postgres > dump
[postgres@localhost ~]$ psql -c "drop table a"
DROP TABLE
[postgres@localhost ~]$ pg_restore --clean -d postgres dump

So limit for plain format is not too strict

Regards

Pavel

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#10)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

[Moving to -hackers]

On Sat, Feb 23, 2013 at 2:51 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

so

* --conditional-drops replaced by --if-exists

Thanks for the fixes, I played around with the patch a bit. I was sort
of expecting this example to work (after setting up the regression
database with `make installcheck`)

pg_dump --clean --if-exists -Fp -d regression --file=regression.sql
createdb test
psql -v ON_ERROR_STOP=1 --single-transaction -d test -f regression.sql

But it fails, first at:
...
DROP TRIGGER IF EXISTS tsvectorupdate ON public.test_tsvector;
ERROR: relation "public.test_tsvector" does not exist

This seems like a shortcoming of DROP TRIGGER ... IF EXISTS, and it
looks like DROP RULE ... IF EXISTS has the same problem. I recall DROP
... IF EXISTS being fixed recently for not to error out if the schema
specified for the object does not exist, and ISTM the same arguments
could be made in favor of fixing DROP TRIGGER/TABLE ... IF EXISTS not
to error out if the table doesn't exist.

yes, I am thinking so it is probably best solution. Without it I
should to generate a DO statement with necessary conditions. :(

I'll prepare patch and proposal.

Working further through the dump of the regression database, these
also present problems for --clean --if-exists dumps:

DROP CAST IF EXISTS (text AS public.casttesttype);
ERROR: type "public.casttesttype" does not exist

DROP OPERATOR IF EXISTS public.<% (point, widget);
ERROR: type "widget" does not exist

DROP FUNCTION IF EXISTS public.pt_in_widget(point, widget);
ERROR: type "widget" does not exist

I'm not sure whether DROP CAST/OPERATOR/FUNCTION IF EXISTS should be
more tolerant of nonexistent types, of if the mess could perhaps be
avoided by dump reordering.

we can raise a warning instead error ?

Regards

Pavel

Note, this usability problem affects unpatched head as well:

pg_dump -Fc -d regression --file=regression.dump
pg_restore --clean -1 -d regression regression.dump
...
pg_restore: [archiver (db)] could not execute query: ERROR: type
"widget" does not exist
Command was: DROP FUNCTION public.widget_out(widget);

(The use here is a little different than the first example above, but
I would still expect this case to work.) The above problems with IF
EXISTS aren't really a problem of the patch per se, but IMO it would
be nice to straighten all the issues out together for 9.4.

* -- additional check, available only with -c option

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

Some comments on the changes:

1. There is at least one IF EXISTS check missing from pg_dump.c, see
for example this statement from a dump of the regression database with
--if-exists:

ALTER TABLE public.nv_child_2010 DROP CONSTRAINT nv_child_2010_d_check;

2. Shouldn't pg_restore get --if-exists as well?

3.
+ printf(_(" --if-exists don't report error if
cleaned object doesn't exist\n"));

This help output bleeds just over our de facto 80-character limit.
Also contractions seem to be avoided elsewhere. It's a little hard to
squeeze a decent explanation into one line, but perhaps:

Use IF EXISTS when dropping objects

would be better. The sgml changes could use some wordsmithing and
grammar fixes. I could clean these up for you in a later version if
you'd like.

4. There seem to be spurious whitespace changes to the function
prototype and declaration for _printTocEntry.

That's all I've had time for so far...

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#14)
1 attachment(s)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

remastered patch

still there is a issue with dependencies

Regards

Pavel Stehule

2013/6/17 Josh Kupershmidt <schmiddy@gmail.com>:

Show quoted text

On Fri, Mar 8, 2013 at 11:58 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I'll see - please, stay tuned to 9.4 first commitfest

Hi Pavel,
Just a reminder, I didn't see this patch in the current commitfest. I
would be happy to spend some more time reviewing if you wish to pursue
the patch.

Josh

Attachments:

conditional-drops.patchapplication/octet-stream; name=conditional-drops.patchDownload
diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index 1ed5e4f..f64c4ba 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -650,6 +650,16 @@ PostgreSQL documentation
      </varlistentry>
 
      <varlistentry>
+      <term><option>--if-exists</option></term>
+      <listitem>
+       <para>
+        It use conditional commands (with <literal>IF EXISTS</literal>
+        clause) for cleaning database schema.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><option>--disable-dollar-quoting</></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml
index 5c6a101..7e5134e 100644
--- a/doc/src/sgml/ref/pg_dumpall.sgml
+++ b/doc/src/sgml/ref/pg_dumpall.sgml
@@ -270,6 +270,16 @@ PostgreSQL documentation
      </varlistentry>
 
      <varlistentry>
+      <term><option>--if-exists</option></term>
+      <listitem>
+       <para>
+        It use conditional commands (with <literal>IF EXISTS</literal>
+        clause) for cleaning database schema.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><option>--disable-dollar-quoting</></term>
       <listitem>
        <para>
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index b456f95..a4c203a 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -113,6 +113,7 @@ typedef struct _restoreOptions
 	char	   *superuser;		/* Username to use as superuser */
 	char	   *use_role;		/* Issue SET ROLE to this */
 	int			dropSchema;
+	int			if_exists;
 	const char *filename;
 	int			dataOnly;
 	int			schemaOnly;
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index cd7669b..7818fe7 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -54,8 +54,9 @@ static const char *modulename = gettext_noop("archiver");
 static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
 	 const int compression, ArchiveMode mode, SetupWorkerPtr setupWorkerPtr);
 static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
-					  ArchiveHandle *AH);
-static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
+					  ArchiveHandle *AH, bool if_exists);
+static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt,
+								 bool isData, bool acl_pass);
 static char *replace_line_endings(const char *str);
 static void _doSetFixedOutputState(ArchiveHandle *AH);
 static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
@@ -234,6 +235,7 @@ RestoreArchive(Archive *AHX)
 	bool		parallel_mode;
 	TocEntry   *te;
 	OutputContext sav;
+	
 
 	AH->stage = STAGE_INITIALIZING;
 
@@ -2886,7 +2888,7 @@ _selectTablespace(ArchiveHandle *AH, const char *tablespace)
  * information used is all that's available in older dump files.
  */
 static void
-_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
+_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH, bool if_exists)
 {
 	const char *type = te->desc;
 
@@ -2953,9 +2955,36 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
 		strcmp(type, "OPERATOR CLASS") == 0 ||
 		strcmp(type, "OPERATOR FAMILY") == 0)
 	{
-		/* Chop "DROP " off the front and make a modifiable copy */
-		char	   *first = pg_strdup(te->dropStmt + 5);
-		char	   *last;
+		char	    *first;
+		char	    *last;
+
+		if (!if_exists)
+		{
+			/* just chop first 5 chars - "DROP", and create a modifiable copy */
+			first = pg_strdup(te->dropStmt + 5);
+		}
+		else
+		{
+			char buffer[40];
+			size_t   l;
+
+			/* IF EXISTS clause should be optional, check it*/
+			snprintf(buffer, sizeof(buffer), "DROP %s%s", type,
+								if_exists ? " IF EXISTS" : "");
+			l = strlen(buffer);
+
+			if (strncmp(te->dropStmt, buffer, l) == 0)
+			{
+				/* append command type to target type */
+				appendPQExpBufferStr(buf, type);
+
+				/* skip first n chars, and create a modifieble copy */
+				first = pg_strdup(te->dropStmt + l);
+			}
+			else
+				/* IF EXISTS clause was not used, simple solution */
+				first = pg_strdup(te->dropStmt + 5);
+		}
 
 		/* point to last character in string */
 		last = first + strlen(first) - 1;
@@ -2976,8 +3005,11 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
 }
 
 static void
-_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
+_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData,
+								      bool acl_pass)
 {
+	int		 if_exists = ropt->if_exists;
+
 	/* ACLs are dumped only during acl pass */
 	if (acl_pass)
 	{
@@ -3135,7 +3167,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
 			PQExpBuffer temp = createPQExpBuffer();
 
 			appendPQExpBuffer(temp, "ALTER ");
-			_getObjectDescription(temp, te, AH);
+			_getObjectDescription(temp, te, AH, if_exists);
 			appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner));
 			ahprintf(AH, "%s\n\n", temp->data);
 			destroyPQExpBuffer(temp);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index becc82b..d6036d1 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -140,6 +140,7 @@ static int	no_security_labels = 0;
 static int	no_synchronized_snapshots = 0;
 static int	no_unlogged_table_data = 0;
 static int	serializable_deferrable = 0;
+static int	if_exists = 0;
 
 
 static void help(const char *progname);
@@ -345,6 +346,7 @@ main(int argc, char **argv)
 		{"attribute-inserts", no_argument, &column_inserts, 1},
 		{"binary-upgrade", no_argument, &binary_upgrade, 1},
 		{"column-inserts", no_argument, &column_inserts, 1},
+		{"if-exists", no_argument, &if_exists, 1},
 		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
 		{"disable-triggers", no_argument, &disable_triggers, 1},
 		{"exclude-table-data", required_argument, NULL, 4},
@@ -576,6 +578,9 @@ main(int argc, char **argv)
 		exit_nicely(1);
 	}
 
+	if (if_exists && !outputClean)
+		exit_horribly(NULL, "option --if-exists requires -c/--clean option\n");
+
 	/* Identify archive format to emit */
 	archiveFormat = parseArchiveFormat(format, &archiveMode);
 
@@ -808,6 +813,7 @@ main(int argc, char **argv)
 	ropt->dropSchema = outputClean;
 	ropt->dataOnly = dataOnly;
 	ropt->schemaOnly = schemaOnly;
+	ropt->if_exists = if_exists;
 	ropt->dumpSections = dumpSections;
 	ropt->aclsSkip = aclsSkip;
 	ropt->superuser = outputSuperuser;
@@ -886,6 +892,7 @@ help(const char *progname)
 	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
 	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
 	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
+	printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
 	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
 	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
 	printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
@@ -2262,7 +2269,8 @@ dumpDatabase(Archive *fout)
 
 	}
 
-	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
+	appendPQExpBuffer(delQry, "DROP DATABASE %s%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(datname));
 
 	dbDumpId = createDumpId();
@@ -7781,7 +7789,9 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 
 	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
 
-	appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
+	appendPQExpBuffer(delq, "DROP SCHEMA %s%s;\n",
+						    if_exists ? "IF EXISTS " : "",
+						    qnspname);
 
 	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
 
@@ -7840,7 +7850,9 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
 	qextname = pg_strdup(fmtId(extinfo->dobj.name));
 
-	appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
+	appendPQExpBuffer(delq, "DROP EXTENSION %s%s;\n",
+						    if_exists ? "IF EXISTS " : "",
+						    qextname);
 
 	if (!binary_upgrade)
 	{
@@ -8014,7 +8026,8 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 	 * CASCADE shouldn't be required here as for normal types since the I/O
 	 * functions are generic and do not get dropped.
 	 */
-	appendPQExpBuffer(delq, "DROP TYPE %s.",
+	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tyinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, "%s;\n",
 					  qtypname);
@@ -8144,7 +8157,8 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 	 * CASCADE shouldn't be required here as for normal types since the I/O
 	 * functions are generic and do not get dropped.
 	 */
-	appendPQExpBuffer(delq, "DROP TYPE %s.",
+	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tyinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, "%s;\n",
 					  qtypname);
@@ -8484,7 +8498,8 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 	 * the type and its I/O functions makes it impossible to drop the type any
 	 * other way.
 	 */
-	appendPQExpBuffer(delq, "DROP TYPE %s.",
+	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tyinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, "%s CASCADE;\n",
 					  qtypname);
@@ -8744,7 +8759,8 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP DOMAIN %s.",
+	appendPQExpBuffer(delq, "DROP DOMAIN %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tyinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, "%s;\n",
 					  qtypname);
@@ -8959,7 +8975,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP TYPE %s.",
+	appendPQExpBuffer(delq, "DROP TYPE %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tyinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, "%s;\n",
 					  qtypname);
@@ -9270,7 +9287,8 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 	else
 		lanschema = NULL;
 
-	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
+	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  qlanname);
 
 	if (useParams)
@@ -9811,7 +9829,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
+	appendPQExpBuffer(delqry, "DROP FUNCTION %s%s.%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(finfo->dobj.namespace->dobj.name),
 					  funcsig);
 
@@ -10029,7 +10048,8 @@ dumpCast(Archive *fout, CastInfo *cast)
 	delqry = createPQExpBuffer();
 	labelq = createPQExpBuffer();
 
-	appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
+	appendPQExpBuffer(delqry, "DROP CAST %s(%s AS %s);\n",
+					if_exists ? "IF EXISTS " : "",
 					getFormattedTypeName(fout, cast->castsource, zeroAsNone),
 				   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
 
@@ -10299,7 +10319,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
+	appendPQExpBuffer(delq, "DROP OPERATOR %s%s.%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(oprinfo->dobj.namespace->dobj.name),
 					  oprid->data);
 
@@ -10585,7 +10606,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
+	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(opcinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s",
 					  fmtId(opcinfo->dobj.name));
@@ -11029,7 +11051,8 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
+	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(opfinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s",
 					  fmtId(opfinfo->dobj.name));
@@ -11203,7 +11226,8 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP COLLATION %s",
+	appendPQExpBuffer(delq, "DROP COLLATION %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(collinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s;\n",
 					  fmtId(collinfo->dobj.name));
@@ -11300,7 +11324,8 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP CONVERSION %s",
+	appendPQExpBuffer(delq, "DROP CONVERSION %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(convinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s;\n",
 					  fmtId(convinfo->dobj.name));
@@ -11544,7 +11569,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
+	appendPQExpBuffer(delq, "DROP AGGREGATE %s%s.%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
 					  aggsig);
 
@@ -11643,7 +11669,8 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
+	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(prsinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s;\n",
 					  fmtId(prsinfo->dobj.name));
@@ -11730,7 +11757,8 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
+	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(dictinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s;\n",
 					  fmtId(dictinfo->dobj.name));
@@ -11796,7 +11824,8 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
+	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tmplinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s;\n",
 					  fmtId(tmplinfo->dobj.name));
@@ -11924,7 +11953,8 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
+	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s%s",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(cfginfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, ".%s;\n",
 					  fmtId(cfginfo->dobj.name));
@@ -12000,7 +12030,8 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 
 	appendPQExpBuffer(q, ";\n");
 
-	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
+	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  qfdwname);
 
 	appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
@@ -12093,7 +12124,8 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 
 	appendPQExpBuffer(q, ";\n");
 
-	appendPQExpBuffer(delq, "DROP SERVER %s;\n",
+	appendPQExpBuffer(delq, "DROP SERVER %s%s;\n",
+					  if_exists ? "IF EXISTS " : "",
 					  qsrvname);
 
 	appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
@@ -12211,7 +12243,9 @@ dumpUserMappings(Archive *fout,
 		appendPQExpBuffer(q, ";\n");
 
 		resetPQExpBuffer(delq);
-		appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
+		appendPQExpBuffer(delq, "DROP USER MAPPING %sFOR %s",
+							    if_exists ? "IF EXISTS " : "",
+							    fmtId(usename));
 		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
 
 		resetPQExpBuffer(tag);
@@ -12820,7 +12854,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		 * DROP must be fully qualified in case same name appears in
 		 * pg_catalog
 		 */
-		appendPQExpBuffer(delq, "DROP VIEW %s.",
+		appendPQExpBuffer(delq, "DROP VIEW %s%s.",
+						  if_exists ? "IF EXISTS " : "",
 						  fmtId(tbinfo->dobj.namespace->dobj.name));
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(tbinfo->dobj.name));
@@ -12893,7 +12928,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		 * DROP must be fully qualified in case same name appears in
 		 * pg_catalog
 		 */
-		appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
+		appendPQExpBuffer(delq, "DROP %s %s%s.", reltypename,
+						  if_exists ? "IF EXISTS " : "",
 						  fmtId(tbinfo->dobj.namespace->dobj.name));
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(tbinfo->dobj.name));
@@ -13427,7 +13463,8 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delq, "ALTER TABLE %s.",
+	appendPQExpBuffer(delq, "ALTER TABLE %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tbinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delq, "%s ",
 					  fmtId(tbinfo->dobj.name));
@@ -13534,7 +13571,8 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 		 * DROP must be fully qualified in case same name appears in
 		 * pg_catalog
 		 */
-		appendPQExpBuffer(delq, "DROP INDEX %s.",
+		appendPQExpBuffer(delq, "DROP INDEX %s%s.",
+						  if_exists ? "IF EXISTS " : "",
 						  fmtId(tbinfo->dobj.namespace->dobj.name));
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(indxinfo->dobj.name));
@@ -13655,7 +13693,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		 * DROP must be fully qualified in case same name appears in
 		 * pg_catalog
 		 */
-		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
+		appendPQExpBuffer(delq, "ALTER TABLE %sONLY %s.",
+						  if_exists ? "IF EXISTS " : "",
 						  fmtId(tbinfo->dobj.namespace->dobj.name));
 		appendPQExpBuffer(delq, "%s ",
 						  fmtId(tbinfo->dobj.name));
@@ -13688,7 +13727,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		 * DROP must be fully qualified in case same name appears in
 		 * pg_catalog
 		 */
-		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
+		appendPQExpBuffer(delq, "ALTER TABLE %sONLY %s.",
+						  if_exists ? "IF EXISTS " : "",
 						  fmtId(tbinfo->dobj.namespace->dobj.name));
 		appendPQExpBuffer(delq, "%s ",
 						  fmtId(tbinfo->dobj.name));
@@ -13957,7 +13997,8 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
+	appendPQExpBuffer(delqry, "DROP SEQUENCE %s%s.",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tbinfo->dobj.namespace->dobj.name));
 	appendPQExpBuffer(delqry, "%s;\n",
 					  fmtId(tbinfo->dobj.name));
@@ -14145,7 +14186,8 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
+	appendPQExpBuffer(delqry, "DROP TRIGGER %s%s ",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(tginfo->dobj.name));
 	appendPQExpBuffer(delqry, "ON %s.",
 					  fmtId(tbinfo->dobj.namespace->dobj.name));
@@ -14485,7 +14527,8 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
-	appendPQExpBuffer(delcmd, "DROP RULE %s ",
+	appendPQExpBuffer(delcmd, "DROP RULE %s%s ",
+					  if_exists ? "IF EXISTS " : "",
 					  fmtId(rinfo->dobj.name));
 	appendPQExpBuffer(delcmd, "ON %s.",
 					  fmtId(tbinfo->dobj.namespace->dobj.name));
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 78f702f..3c5c340 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -71,6 +71,7 @@ static bool verbose = false;
 
 static int	binary_upgrade = 0;
 static int	column_inserts = 0;
+static int	if_exists = 0;
 static int	disable_dollar_quoting = 0;
 static int	disable_triggers = 0;
 static int	inserts = 0;
@@ -117,6 +118,7 @@ main(int argc, char *argv[])
 		{"attribute-inserts", no_argument, &column_inserts, 1},
 		{"binary-upgrade", no_argument, &binary_upgrade, 1},
 		{"column-inserts", no_argument, &column_inserts, 1},
+		{"if-exists", no_argument, &if_exists, 1},
 		{"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
 		{"disable-triggers", no_argument, &disable_triggers, 1},
 		{"inserts", no_argument, &inserts, 1},
@@ -348,6 +350,8 @@ main(int argc, char *argv[])
 		appendPQExpBuffer(pgdumpopts, " --binary-upgrade");
 	if (column_inserts)
 		appendPQExpBuffer(pgdumpopts, " --column-inserts");
+	if (if_exists)
+		appendPQExpBuffer(pgdumpopts, " --if-exists");
 	if (disable_dollar_quoting)
 		appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting");
 	if (disable_triggers)
@@ -559,6 +563,7 @@ help(void)
 	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
 	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
 	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
+	printf(_("  --if-exists                  don't report error if cleaned object doesn't exist\n"));
 	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
 	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
 	printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
#19Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#18)
1 attachment(s)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

I am sending a patch that removes strict requirements for DROP IF
EXISTS statements. This behave is similar to our ALTER IF EXISTS
behave now.

postgres=# DROP CAST IF EXISTS (sss AS public.casttesttype);
NOTICE: types "sss" and "public.casttesttype" does not exist, skipping
DROP CAST
postgres=# DROP FUNCTION IF EXISTS public.pt_in_widget(point, widget);
NOTICE: function public.pt_in_widget(point,widget) does not exist, skipping
DROP FUNCTION
postgres=# DROP OPERATOR IF EXISTS public.<% (point, widget);
NOTICE: operator public.<% does not exist, skipping
DROP OPERATOR
postgres=# DROP TRIGGER test_trigger_exists ON no_such_table;
ERROR: relation "no_such_table" does not exist
postgres=# DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
NOTICE: trigger "test_trigger_exists" for table "no_such_table" does
not exist, skipping
DROP TRIGGER

This functionality is necessary for correct quite reload from dump
without possible warnings

Regards

Pavel

2013/7/2 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

Hello

remastered patch

still there is a issue with dependencies

Regards

Pavel Stehule

2013/6/17 Josh Kupershmidt <schmiddy@gmail.com>:

On Fri, Mar 8, 2013 at 11:58 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I'll see - please, stay tuned to 9.4 first commitfest

Hi Pavel,
Just a reminder, I didn't see this patch in the current commitfest. I
would be happy to spend some more time reviewing if you wish to pursue
the patch.

Josh

Attachments:

drop-if-exists-no-double-check.patchapplication/octet-stream; name=drop-if-exists-no-double-check.patchDownload
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 580,587 **** get_object_address(ObjectType objtype, List *objname, List *objargs,
  				{
  					TypeName   *sourcetype = (TypeName *) linitial(objname);
  					TypeName   *targettype = (TypeName *) linitial(objargs);
! 					Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
! 					Oid			targettypeid = typenameTypeId(NULL, targettype);
  
  					address.classId = CastRelationId;
  					address.objectId =
--- 580,595 ----
  				{
  					TypeName   *sourcetype = (TypeName *) linitial(objname);
  					TypeName   *targettype = (TypeName *) linitial(objargs);
! 					Oid			sourcetypeid = typenameTypeId_extended(NULL,
! 											    sourcetype, missing_ok);
! 					Oid			targettypeid = typenameTypeId_extended(NULL,
! 											    targettype, missing_ok);
! 
! 					if (!OidIsValid(sourcetypeid) || !OidIsValid(targettypeid))
! 					{
! 						address.objectId = InvalidOid;
! 						break;
! 					}
  
  					address.classId = CastRelationId;
  					address.objectId =
***************
*** 942,983 **** get_object_address_relobject(ObjectType objtype, List *objname,
  
  		/* Extract relation name and open relation. */
  		relname = list_truncate(list_copy(objname), nnames - 1);
- 		relation = heap_openrv(makeRangeVarFromNameList(relname),
- 							   AccessShareLock);
- 		reloid = RelationGetRelid(relation);
  
! 		switch (objtype)
  		{
! 			case OBJECT_RULE:
! 				address.classId = RewriteRelationId;
! 				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
! 				address.objectSubId = 0;
! 				break;
! 			case OBJECT_TRIGGER:
! 				address.classId = TriggerRelationId;
! 				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
! 				address.objectSubId = 0;
! 				break;
! 			case OBJECT_CONSTRAINT:
! 				address.classId = ConstraintRelationId;
! 				address.objectId =
! 					get_relation_constraint_oid(reloid, depname, missing_ok);
! 				address.objectSubId = 0;
! 				break;
! 			default:
! 				elog(ERROR, "unrecognized objtype: %d", (int) objtype);
! 				/* placate compiler, which doesn't know elog won't return */
! 				address.classId = InvalidOid;
! 				address.objectId = InvalidOid;
! 				address.objectSubId = 0;
! 		}
  
! 		/* Avoid relcache leak when object not found. */
! 		if (!OidIsValid(address.objectId))
! 		{
! 			heap_close(relation, AccessShareLock);
! 			relation = NULL;	/* department of accident prevention */
! 			return address;
  		}
  	}
  
--- 950,997 ----
  
  		/* Extract relation name and open relation. */
  		relname = list_truncate(list_copy(objname), nnames - 1);
  
! 		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
! 									   AccessShareLock,
! 									   missing_ok);
! 									 
! 		if (relation != NULL)
  		{
! 			reloid = RelationGetRelid(relation);
  
! 			switch (objtype)
! 			{
! 				case OBJECT_RULE:
! 					address.classId = RewriteRelationId;
! 					address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
! 					address.objectSubId = 0;
! 					break;
! 				case OBJECT_TRIGGER:
! 					address.classId = TriggerRelationId;
! 					address.objectId = get_trigger_oid(reloid, depname, missing_ok);
! 					address.objectSubId = 0;
! 					break;
! 				case OBJECT_CONSTRAINT:
! 					address.classId = ConstraintRelationId;
! 					address.objectId =
! 						get_relation_constraint_oid(reloid, depname, missing_ok);
! 					address.objectSubId = 0;
! 					break;
! 				default:
! 					elog(ERROR, "unrecognized objtype: %d", (int) objtype);
! 					/* placate compiler, which doesn't know elog won't return */
! 					address.classId = InvalidOid;
! 					address.objectId = InvalidOid;
! 					address.objectSubId = 0;
! 			}
! 
! 			/* Avoid relcache leak when object not found. */
! 			if (!OidIsValid(address.objectId))
! 			{
! 				heap_close(relation, AccessShareLock);
! 				relation = NULL;	/* department of accident prevention */
! 				return address;
! 			}
  		}
  	}
  
*** a/src/backend/commands/dropcmds.c
--- b/src/backend/commands/dropcmds.c
***************
*** 194,204 **** does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
  			name = NameListToString(objname);
  			break;
  		case OBJECT_CAST:
! 			msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
! 			name = format_type_be(typenameTypeId(NULL,
! 											(TypeName *) linitial(objname)));
! 			args = format_type_be(typenameTypeId(NULL,
! 											(TypeName *) linitial(objargs)));
  			break;
  		case OBJECT_TRIGGER:
  			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
--- 194,233 ----
  			name = NameListToString(objname);
  			break;
  		case OBJECT_CAST:
! 			{
! 				Oid	typid1,
! 					    typid2;
! 				/*
! 				 * when one from requested types is unknown, then do nothing,
! 				 * because notice was raised already.
! 				 */
! 				typid1 = typenameTypeId_extended(NULL, (TypeName *) linitial(objname), true);
! 				typid2 = typenameTypeId_extended(NULL, (TypeName *) linitial(objargs), true);
! 
! 				if (OidIsValid(typid1) && OidIsValid(typid2))
! 				{
! 					msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
! 					name = format_type_be(typid1);
! 					args = format_type_be(typid2);
! 				}
! 				else if (OidIsValid(typid1) && !OidIsValid(typid2))
! 				{
! 					msg = gettext_noop("type \"%s\" does not exist, skipping");
! 					name = TypeNameToString((TypeName *) linitial(objargs));
! 
! 				}
! 				else if (!OidIsValid(typid1) && OidIsValid(typid2))
! 				{
! 					msg = gettext_noop("type \"%s\" does not exist, skipping");
! 					name = TypeNameToString((TypeName *) linitial(objname));
! 				}
! 				else
! 				{
! 					msg = gettext_noop("types \"%s\" and \"%s\" does not exist, skipping");
! 					name = TypeNameToString((TypeName *) linitial(objname));
! 					args = TypeNameToString((TypeName *) linitial(objargs));
! 				}
! 			}
  			break;
  		case OBJECT_TRIGGER:
  			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 4484,4490 **** ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
  							MaxHeapAttributeNumber)));
  	}
  
! 	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
  	tform = (Form_pg_type) GETSTRUCT(typeTuple);
  	typeOid = HeapTupleGetOid(typeTuple);
  
--- 4484,4490 ----
  							MaxHeapAttributeNumber)));
  	}
  
! 	typeTuple = typenameType(NULL, colDef->typeName, &typmod, false);
  	tform = (Form_pg_type) GETSTRUCT(typeTuple);
  	typeOid = HeapTupleGetOid(typeTuple);
  
***************
*** 7596,7602 **** ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
  						colName)));
  
  	/* Look up the target type (should not fail, since prep found it) */
! 	typeTuple = typenameType(NULL, typeName, &targettypmod);
  	tform = (Form_pg_type) GETSTRUCT(typeTuple);
  	targettype = HeapTupleGetOid(typeTuple);
  	/* And the collation */
--- 7596,7602 ----
  						colName)));
  
  	/* Look up the target type (should not fail, since prep found it) */
! 	typeTuple = typenameType(NULL, typeName, &targettypmod, false);
  	tform = (Form_pg_type) GETSTRUCT(typeTuple);
  	targettype = HeapTupleGetOid(typeTuple);
  	/* And the collation */
***************
*** 9812,9818 **** ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
  	HeapTuple	classtuple;
  
  	/* Validate the type. */
! 	typetuple = typenameType(NULL, ofTypename, NULL);
  	check_of_type(typetuple);
  	typeid = HeapTupleGetOid(typetuple);
  
--- 9812,9818 ----
  	HeapTuple	classtuple;
  
  	/* Validate the type. */
! 	typetuple = typenameType(NULL, ofTypename, NULL, false);
  	check_of_type(typetuple);
  	typeid = HeapTupleGetOid(typetuple);
  
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 307,313 **** DefineType(List *names, List *parameters)
  		Type		likeType;
  		Form_pg_type likeForm;
  
! 		likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
  		likeForm = (Form_pg_type) GETSTRUCT(likeType);
  		internalLength = likeForm->typlen;
  		byValue = likeForm->typbyval;
--- 307,313 ----
  		Type		likeType;
  		Form_pg_type likeForm;
  
! 		likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL, false);
  		likeForm = (Form_pg_type) GETSTRUCT(likeType);
  		internalLength = likeForm->typlen;
  		byValue = likeForm->typbyval;
***************
*** 741,747 **** DefineDomain(CreateDomainStmt *stmt)
  	/*
  	 * Look up the base type.
  	 */
! 	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
  	baseType = (Form_pg_type) GETSTRUCT(typeTup);
  	basetypeoid = HeapTupleGetOid(typeTup);
  
--- 741,747 ----
  	/*
  	 * Look up the base type.
  	 */
! 	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod, false);
  	baseType = (Form_pg_type) GETSTRUCT(typeTup);
  	basetypeoid = HeapTupleGetOid(typeTup);
  
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
***************
*** 1574,1590 **** LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
   *		Convenience routine to look up a type, silently accepting shell types
   */
  static Oid
! LookupTypeNameOid(const TypeName *typename)
  {
  	Oid			result;
  	Type		typtup;
  
  	typtup = LookupTypeName(NULL, typename, NULL);
  	if (typtup == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("type \"%s\" does not exist",
  						TypeNameToString(typename))));
  	result = typeTypeId(typtup);
  	ReleaseSysCache(typtup);
  	return result;
--- 1574,1595 ----
   *		Convenience routine to look up a type, silently accepting shell types
   */
  static Oid
! LookupTypeNameOid(const TypeName *typename, bool missing_ok)
  {
  	Oid			result;
  	Type		typtup;
  
  	typtup = LookupTypeName(NULL, typename, NULL);
  	if (typtup == NULL)
+ 	{
+ 		if (missing_ok)
+ 			return InvalidOid;
+ 
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("type \"%s\" does not exist",
  						TypeNameToString(typename))));
+ 	}
  	result = typeTypeId(typtup);
  	ReleaseSysCache(typtup);
  	return result;
***************
*** 1617,1623 **** LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
  	{
  		TypeName   *t = (TypeName *) lfirst(args_item);
  
! 		argoids[i] = LookupTypeNameOid(t);
  		args_item = lnext(args_item);
  	}
  
--- 1622,1633 ----
  	{
  		TypeName   *t = (TypeName *) lfirst(args_item);
  
! 		if (!OidIsValid(argoids[i] = LookupTypeNameOid(t, noError)))
! 		{
! 			Assert(noError);
! 			return InvalidOid;
! 		}
! 
  		args_item = lnext(args_item);
  	}
  
***************
*** 1657,1663 **** LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
  	{
  		TypeName   *t = (TypeName *) lfirst(lc);
  
! 		argoids[i] = LookupTypeNameOid(t);
  		i++;
  	}
  
--- 1667,1678 ----
  	{
  		TypeName   *t = (TypeName *) lfirst(lc);
  
! 		if (!OidIsValid(argoids[i] = LookupTypeNameOid(t, noError)))
! 		{
! 			Assert(noError);
! 			return InvalidOid;
! 		}
! 
  		i++;
  	}
  
*** a/src/backend/parser/parse_oper.c
--- b/src/backend/parser/parse_oper.c
***************
*** 148,159 **** LookupOperNameTypeNames(ParseState *pstate, List *opername,
  	if (oprleft == NULL)
  		leftoid = InvalidOid;
  	else
! 		leftoid = typenameTypeId(pstate, oprleft);
  
  	if (oprright == NULL)
  		rightoid = InvalidOid;
  	else
! 		rightoid = typenameTypeId(pstate, oprright);
  
  	return LookupOperName(pstate, opername, leftoid, rightoid,
  						  noError, location);
--- 148,159 ----
  	if (oprleft == NULL)
  		leftoid = InvalidOid;
  	else
! 		leftoid = typenameTypeId_extended(pstate, oprleft, noError);
  
  	if (oprright == NULL)
  		rightoid = InvalidOid;
  	else
! 		rightoid = typenameTypeId_extended(pstate, oprright, noError);
  
  	return LookupOperName(pstate, opername, leftoid, rightoid,
  						  noError, location);
*** a/src/backend/parser/parse_type.c
--- b/src/backend/parser/parse_type.c
***************
*** 192,208 **** LookupTypeName(ParseState *pstate, const TypeName *typeName,
   * Callers of this can therefore assume the result is a fully valid type.
   */
  Type
! typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
  {
  	Type		tup;
  
  	tup = LookupTypeName(pstate, typeName, typmod_p);
  	if (tup == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("type \"%s\" does not exist",
  						TypeNameToString(typeName)),
  				 parser_errposition(pstate, typeName->location)));
  	if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
--- 192,216 ----
   * Callers of this can therefore assume the result is a fully valid type.
   */
  Type
! typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p,
! 						   bool missing_ok)
  {
  	Type		tup;
  
  	tup = LookupTypeName(pstate, typeName, typmod_p);
  	if (tup == NULL)
+ 	{
+ 		if (missing_ok)
+ 			/* be quite, caller is responsible to raise message */
+ 			return NULL;
+ 
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("type \"%s\" does not exist",
  						TypeNameToString(typeName)),
  				 parser_errposition(pstate, typeName->location)));
+ 	}
+ 
  	if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
***************
*** 224,230 **** typenameTypeId(ParseState *pstate, const TypeName *typeName)
  	Oid			typoid;
  	Type		tup;
  
! 	tup = typenameType(pstate, typeName, NULL);
  	typoid = HeapTupleGetOid(tup);
  	ReleaseSysCache(tup);
  
--- 232,265 ----
  	Oid			typoid;
  	Type		tup;
  
! 	tup = typenameType(pstate, typeName, NULL, false);
! 	typoid = HeapTupleGetOid(tup);
! 	ReleaseSysCache(tup);
! 
! 	return typoid;
! }
! 
! /*
!  * typenameTypeId_extended - given a TypeName, return the type's OID
!  *
!  * This is similar to typenameType, but we only hand back the type OID
!  * not the syscache entry. When missing_ok is true, then doesn't raise
!  * error when type is not exists.
!  */
! Oid
! typenameTypeId_extended(ParseState *pstate, const TypeName *typeName,
! 				    bool missing_ok)
! {
! 	Oid			typoid;
! 	Type		tup;
! 
! 	tup = typenameType(pstate, typeName, NULL, missing_ok);
! 	if (tup == NULL)
! 	{
! 		Assert(missing_ok);
! 		return InvalidOid;
! 	}
! 
  	typoid = HeapTupleGetOid(tup);
  	ReleaseSysCache(tup);
  
***************
*** 243,249 **** typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
  {
  	Type		tup;
  
! 	tup = typenameType(pstate, typeName, typmod_p);
  	*typeid_p = HeapTupleGetOid(tup);
  	ReleaseSysCache(tup);
  }
--- 278,284 ----
  {
  	Type		tup;
  
! 	tup = typenameType(pstate, typeName, typmod_p, false);
  	*typeid_p = HeapTupleGetOid(tup);
  	ReleaseSysCache(tup);
  }
*** a/src/backend/parser/parse_utilcmd.c
--- b/src/backend/parser/parse_utilcmd.c
***************
*** 942,948 **** transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
  
  	AssertArg(ofTypename);
  
! 	tuple = typenameType(NULL, ofTypename, NULL);
  	check_of_type(tuple);
  	ofTypeId = HeapTupleGetOid(tuple);
  	ofTypename->typeOid = ofTypeId;		/* cached for later */
--- 942,948 ----
  
  	AssertArg(ofTypename);
  
! 	tuple = typenameType(NULL, ofTypename, NULL, false);
  	check_of_type(tuple);
  	ofTypeId = HeapTupleGetOid(tuple);
  	ofTypename->typeOid = ofTypeId;		/* cached for later */
***************
*** 2652,2658 **** transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
  	 * All we really need to do here is verify that the type is valid,
  	 * including any collation spec that might be present.
  	 */
! 	Type		ctype = typenameType(cxt->pstate, column->typeName, NULL);
  
  	if (column->collClause)
  	{
--- 2652,2658 ----
  	 * All we really need to do here is verify that the type is valid,
  	 * including any collation spec that might be present.
  	 */
! 	Type		ctype = typenameType(cxt->pstate, column->typeName, NULL, false);
  
  	if (column->collClause)
  	{
*** a/src/include/parser/parse_type.h
--- b/src/include/parser/parse_type.h
***************
*** 22,29 **** typedef HeapTuple Type;
  extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
  			   int32 *typmod_p);
  extern Type typenameType(ParseState *pstate, const TypeName *typeName,
! 			 int32 *typmod_p);
  extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
  extern void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
  					 Oid *typeid_p, int32 *typmod_p);
  
--- 22,31 ----
  extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
  			   int32 *typmod_p);
  extern Type typenameType(ParseState *pstate, const TypeName *typeName,
! 			 int32 *typmod_p, bool missing_ok);
  extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
+ extern Oid	typenameTypeId_extended(ParseState *pstate,
+ 					 const TypeName *typeName, bool missing_ok);
  extern void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
  					 Oid *typeid_p, int32 *typmod_p);
  
*** a/src/test/regress/expected/drop_if_exists.out
--- b/src/test/regress/expected/drop_if_exists.out
***************
*** 173,179 **** NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, s
  DROP TRIGGER test_trigger_exists ON no_such_table;
  ERROR:  relation "no_such_table" does not exist
  DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
! ERROR:  relation "no_such_table" does not exist
  CREATE TRIGGER test_trigger_exists
      BEFORE UPDATE ON test_exists
      FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
--- 173,179 ----
  DROP TRIGGER test_trigger_exists ON no_such_table;
  ERROR:  relation "no_such_table" does not exist
  DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
! NOTICE:  trigger "test_trigger_exists" for table "no_such_table" does not exist, skipping
  CREATE TRIGGER test_trigger_exists
      BEFORE UPDATE ON test_exists
      FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
***************
*** 186,192 **** NOTICE:  rule "test_rule_exists" for relation "test_exists" does not exist, skip
  DROP RULE test_rule_exists ON no_such_table;
  ERROR:  relation "no_such_table" does not exist
  DROP RULE IF EXISTS test_rule_exists ON no_such_table;
! ERROR:  relation "no_such_table" does not exist
  CREATE RULE test_rule_exists AS ON INSERT TO test_exists
      DO INSTEAD
      INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
--- 186,192 ----
  DROP RULE test_rule_exists ON no_such_table;
  ERROR:  relation "no_such_table" does not exist
  DROP RULE IF EXISTS test_rule_exists ON no_such_table;
! NOTICE:  rule "test_rule_exists" for relation "no_such_table" does not exist, skipping
  CREATE RULE test_rule_exists AS ON INSERT TO test_exists
      DO INSTEAD
      INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
#20Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#19)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Fri, Jul 5, 2013 at 12:16 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I am sending a patch that removes strict requirements for DROP IF
EXISTS statements. This behave is similar to our ALTER IF EXISTS
behave now.

+1 for this idea. But this patch should be treated as a separate issue
from the use of IF EXISTS in pg_dump/pg_restore, right? If so, I
suggest starting a new thread about this patch to make reviewing
easier.

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Pavel Stehule
pavel.stehule@gmail.com
In reply to: Josh Kupershmidt (#20)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Yes, I wrote a separate patch for next commitfest.
Dne 10.7.2013 16:54 "Josh Kupershmidt" <schmiddy@gmail.com> napsal(a):

Show quoted text

On Fri, Jul 5, 2013 at 12:16 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

I am sending a patch that removes strict requirements for DROP IF
EXISTS statements. This behave is similar to our ALTER IF EXISTS
behave now.

+1 for this idea. But this patch should be treated as a separate issue
from the use of IF EXISTS in pg_dump/pg_restore, right? If so, I
suggest starting a new thread about this patch to make reviewing
easier.

Josh

#22Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#16)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Tue, Jul 2, 2013 at 5:39 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

On Fri, Mar 8, 2013 at 2:23 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/3/8 Josh Kupershmidt <schmiddy@gmail.com>:

Cool. I think it would also be useful to check that --clean may only
be used with --format=p to avoid any confusion there. (This issue
could be addressed in a separate patch if you'd rather not lard this
patch.)

no

some people - like we in our company would to use this feature for
quiet and strict mode for plain text format too.

enabling this feature has zero overhead so there are no reason block
it anywhere.

I'm not sure I understand what you're getting at, but maybe my
proposal wasn't so clear. Right now, you can specify --clean along
with -Fc to pg_dump, and pg_dump will not complain even though this
combination is nonsense. I am proposing that pg_dump error out in this
case, i.e.

$ pg_dump -Fc --file=test.dump --clean -d test
pg_dump: option --clean only valid with plain format dump

Although this lack of an error a (IMO) misfeature of existing pg_dump,
so if you'd rather leave this issue aside for your patch, that is
fine.

I tested last patch and I am thinking so this patch has sense for
custom format too

[postgres@localhost ~]$ /usr/local/pgsql/bin/pg_dump --clean -t a
-Fc postgres > dump
[postgres@localhost ~]$ psql -c "drop table a"
DROP TABLE
[postgres@localhost ~]$ pg_restore --clean -d postgres dump
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 171; 1259 16462 TABLE
a postgres
pg_restore: [archiver (db)] could not execute query: ERROR: table "a"
does not exist
Command was: DROP TABLE public.a;

WARNING: errors ignored on restore: 1

[postgres@localhost ~]$ /usr/local/pgsql/bin/pg_dump --if-exist
--clean -t a -Fc postgres > dump
[postgres@localhost ~]$ psql -c "drop table a"
DROP TABLE
[postgres@localhost ~]$ pg_restore --clean -d postgres dump

So limit for plain format is not too strict

I'm not sure I understand what you're proposing here, but for the
record I really don't think it's a good idea to encourage the use of
pg_dump -Fc --clean ...

Right now, we don't error out on this combination of command-line
options, but the --clean is effectively a no-op; you have to tell
pg_restore to use --clean. IMO, this is basically how it should be:
pg_dump, at least in custom-format, is preserving the contents of your
database with the understanding that you will use pg_restore wish to
restore from this dump in a variety of possible ways. Putting
restrictions like --clean into the custom-format dump file just makes
that dump file less useful overall.

Although it's still not clear to me why the examples you showed above
used *both* `pg_dump -Fc --clean ...` and `pg_restore --clean ...`
together. Surely the user should be specifying this preference in only
one place?

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Josh Kupershmidt
schmiddy@gmail.com
In reply to: Pavel Stehule (#18)
Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Tue, Jul 2, 2013 at 7:47 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hello

remastered patch

still there is a issue with dependencies

Several of the issues from my last review [1]/messages/by-id/CAK3UJRG__4=+f46XaMiqA80f_-BQhJcpFwyp8g8fpSPqj-JSzA@mail.gmail.com seem to still be present
in this patch, such as review notes #1 and #4.

And as discussed previously, I think that the --clean option belongs
solely with pg_restore for custom-format dumps. The way the patch
handles this is rather confusing, forcing the user to do:

$ pg_dump -Fc --clean --if-exists --file=backup.dump ...
and then:
$ pg_restore --clean ... backup.dump (without --if-exists)

to get the desired behavior.

Josh

[1]: /messages/by-id/CAK3UJRG__4=+f46XaMiqA80f_-BQhJcpFwyp8g8fpSPqj-JSzA@mail.gmail.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Satoshi Nagayasu
snaga@uptime.jp
In reply to: Pavel Stehule (#19)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

(2013/07/06 1:16), Pavel Stehule wrote:

I am sending a patch that removes strict requirements for DROP IF
EXISTS statements. This behave is similar to our ALTER IF EXISTS
behave now.

postgres=# DROP CAST IF EXISTS (sss AS public.casttesttype);
NOTICE: types "sss" and "public.casttesttype" does not exist, skipping
DROP CAST
postgres=# DROP FUNCTION IF EXISTS public.pt_in_widget(point, widget);
NOTICE: function public.pt_in_widget(point,widget) does not exist, skipping
DROP FUNCTION
postgres=# DROP OPERATOR IF EXISTS public.<% (point, widget);
NOTICE: operator public.<% does not exist, skipping
DROP OPERATOR
postgres=# DROP TRIGGER test_trigger_exists ON no_such_table;
ERROR: relation "no_such_table" does not exist
postgres=# DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
NOTICE: trigger "test_trigger_exists" for table "no_such_table" does
not exist, skipping
DROP TRIGGER

This functionality is necessary for correct quite reload from dump
without possible warnings

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing trigger
and non-existing table? Or just only for non-existing trigger?

I've not understood the pg_restore issue precisely so far,
but IMHO "DROP TRIGGER IF EXISTS" means "if the _trigger_ exists",
not "if the _table_ exists".

Is this a correct and/or an expected behavior?

Sorry if I missed some consensus which we already made.

Any comments?

Regards,
--
Satoshi Nagayasu <snaga@uptime.jp>
Uptime Technologies, LLC. http://www.uptime.jp

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Pavel Stehule
pavel.stehule@gmail.com
In reply to: Satoshi Nagayasu (#24)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp>

(2013/07/06 1:16), Pavel Stehule wrote:

I am sending a patch that removes strict requirements for DROP IF
EXISTS statements. This behave is similar to our ALTER IF EXISTS
behave now.

postgres=# DROP CAST IF EXISTS (sss AS public.casttesttype);
NOTICE: types "sss" and "public.casttesttype" does not exist, skipping
DROP CAST
postgres=# DROP FUNCTION IF EXISTS public.pt_in_widget(point, widget);
NOTICE: function public.pt_in_widget(point,**widget) does not exist,
skipping
DROP FUNCTION
postgres=# DROP OPERATOR IF EXISTS public.<% (point, widget);
NOTICE: operator public.<% does not exist, skipping
DROP OPERATOR
postgres=# DROP TRIGGER test_trigger_exists ON no_such_table;
ERROR: relation "no_such_table" does not exist
postgres=# DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
NOTICE: trigger "test_trigger_exists" for table "no_such_table" does
not exist, skipping
DROP TRIGGER

This functionality is necessary for correct quite reload from dump
without possible warnings

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing trigger
and non-existing table? Or just only for non-existing trigger?

My opinion is so, both variants should be ignored - it should be fully
fault tolerant in this use case.

Regards

Pavel

Show quoted text

I've not understood the pg_restore issue precisely so far,
but IMHO "DROP TRIGGER IF EXISTS" means "if the _trigger_ exists",
not "if the _table_ exists".

Is this a correct and/or an expected behavior?

Sorry if I missed some consensus which we already made.

Any comments?

Regards,
--
Satoshi Nagayasu <snaga@uptime.jp>
Uptime Technologies, LLC. http://www.uptime.jp

#26Andrew Dunstan
andrew@dunslane.net
In reply to: Pavel Stehule (#25)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp <mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing trigger
and non-existing table? Or just only for non-existing trigger?

My opinion is so, both variants should be ignored - it should be fully
fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with
Pavel. If the table doesn't exist, neither does the trigger, and the
whole point of the 'IF EXISTS' variants is to provide the ability to
issue DROP commands that don't fail if their target is missing.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Josh Kupershmidt
schmiddy@gmail.com
In reply to: Andrew Dunstan (#26)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Thu, Oct 10, 2013 at 12:54 PM, Andrew Dunstan <andrew@dunslane.net> wrote:

This thread seems to have gone cold, but I'm inclined to agree with Pavel.
If the table doesn't exist, neither does the trigger, and the whole point of
the 'IF EXISTS' variants is to provide the ability to issue DROP commands
that don't fail if their target is missing.

+1 from me as well.

Also, Pavel, this patch is still listed as 'Needs Review' in the CF
app, but I haven't seen a response to the concerns in my last message.

Josh

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#28Andres Freund
andres@2ndquadrant.com
In reply to: Andrew Dunstan (#26)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp <mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing trigger
and non-existing table? Or just only for non-existing trigger?

My opinion is so, both variants should be ignored - it should be fully
fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with Pavel.
If the table doesn't exist, neither does the trigger, and the whole point of
the 'IF EXISTS' variants is to provide the ability to issue DROP commands
that don't fail if their target is missing.

-1, this seems to likely to just hide typos.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#29Andrew Dunstan
andrew@dunslane.net
In reply to: Andres Freund (#28)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 10/14/2013 05:44 PM, Andres Freund wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp <mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing trigger
and non-existing table? Or just only for non-existing trigger?

My opinion is so, both variants should be ignored - it should be fully
fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with Pavel.
If the table doesn't exist, neither does the trigger, and the whole point of
the 'IF EXISTS' variants is to provide the ability to issue DROP commands
that don't fail if their target is missing.

-1, this seems to likely to just hide typos.

So if I say

DROP TRIGGER IF EXISTS foo ON bar;

you're ok with succeeding if foo is a typo, but not if bar is?

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Andres Freund
andres@2ndquadrant.com
In reply to: Andrew Dunstan (#29)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-10-14 17:59:25 -0400, Andrew Dunstan wrote:

On 10/14/2013 05:44 PM, Andres Freund wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp <mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing trigger
and non-existing table? Or just only for non-existing trigger?

My opinion is so, both variants should be ignored - it should be fully
fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with Pavel.
If the table doesn't exist, neither does the trigger, and the whole point of
the 'IF EXISTS' variants is to provide the ability to issue DROP commands
that don't fail if their target is missing.

-1, this seems to likely to just hide typos.

So if I say

DROP TRIGGER IF EXISTS foo ON bar;

you're ok with succeeding if foo is a typo, but not if bar is?

Yes.

Normally you won't do DROP TRIGGER if you don't need the table in the
first place, in that case you can just DROP TABLE.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#31Tomas Vondra
tv@fuzzy.cz
In reply to: Andres Freund (#28)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hi,

On 14.10.2013 23:44, Andres Freund wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp
<mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing
trigger and non-existing table? Or just only for non-existing
trigger?

My opinion is so, both variants should be ignored - it should be
fully fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with
Pavel. If the table doesn't exist, neither does the trigger, and
the whole point of the 'IF EXISTS' variants is to provide the
ability to issue DROP commands that don't fail if their target is
missing.

-1, this seems to likely to just hide typos.

Not sure I agree with your reasoning. Isn't that equally true for 'IF
EXISTS' clause with all commands in general? Why should we use "likely
to hide typos" argument in this case and not the others?

Or do you object only to extending DROP TRIGGER IF EXISTS to "if table
and trigger exists"? It seems natural to me that "no table" => "no
trigger" so I'm fine with this interpretation, just like Andrew.

The purpose of this patch was to add support for quiet "pg_restore
--clean" and pg_restore should not do typos (if it does, we're in much
deeper troubles I guess).

If you're concerned about users doing typos, they may as well do typos
in the trigger name with exactly the same result (trigger not dropped
without any kind of error message).

I see no reason to support DROP TRIGGER IF EXISTS but restrict the IF
EXISTS clause only to the trigger on the grounds of typos.

So +1 from me, both to the patch and graceful handling of missing table.

kind regards
Tomas

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#32Andres Freund
andres@2ndquadrant.com
In reply to: Tomas Vondra (#31)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-10-15 00:23:15 +0200, Tomas Vondra wrote:

Hi,

On 14.10.2013 23:44, Andres Freund wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp
<mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing
trigger and non-existing table? Or just only for non-existing
trigger?

My opinion is so, both variants should be ignored - it should be
fully fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with
Pavel. If the table doesn't exist, neither does the trigger, and
the whole point of the 'IF EXISTS' variants is to provide the
ability to issue DROP commands that don't fail if their target is
missing.

-1, this seems to likely to just hide typos.

Not sure I agree with your reasoning. Isn't that equally true for 'IF
EXISTS' clause with all commands in general? Why should we use "likely
to hide typos" argument in this case and not the others?

Because there simply is no reason to issue a DROP TRIGGER IF EXISTS if
you don't need the contents of the table. In that case you can just
issue a DROP TABLE IF EXISTS and start anew.

The purpose of this patch was to add support for quiet "pg_restore
--clean" and pg_restore should not do typos (if it does, we're in much
deeper troubles I guess).

Why does that even have to do anything for triggers? Emitting DROP TABLE
should be enough.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#33Josh Kupershmidt
schmiddy@gmail.com
In reply to: Josh Kupershmidt (#27)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Mon, Oct 14, 2013 at 5:38 PM, Josh Kupershmidt <schmiddy@gmail.com> wrote:

Also, Pavel, this patch is still listed as 'Needs Review' in the CF
app, but I haven't seen a response to the concerns in my last message.

It looks like this patch has been imported into the 2013-11 CF [1]https://commitfest.postgresql.org/action/patch_view?id=1174 and
marked "Needs Review". I looked at the version of the patch pointed to
in that CF entry back in July, and noted [2]/messages/by-id/CAK3UJREth9DVL5U7ewOLQYhXF7EcV5BABFE+pzPQjkPfqbW=vQ@mail.gmail.com several problems that
still seemed to be present in the patch, for which I never saw a
followup from Pavel. IMO this patch should have gotten marked
"Returned with Feedback" pending a response from Pavel.

Josh

[1]: https://commitfest.postgresql.org/action/patch_view?id=1174
[2]: /messages/by-id/CAK3UJREth9DVL5U7ewOLQYhXF7EcV5BABFE+pzPQjkPfqbW=vQ@mail.gmail.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#34Robert Haas
robertmhaas@gmail.com
In reply to: Josh Kupershmidt (#33)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Tue, Oct 22, 2013 at 9:37 PM, Josh Kupershmidt <schmiddy@gmail.com> wrote:

On Mon, Oct 14, 2013 at 5:38 PM, Josh Kupershmidt <schmiddy@gmail.com> wrote:

Also, Pavel, this patch is still listed as 'Needs Review' in the CF
app, but I haven't seen a response to the concerns in my last message.

It looks like this patch has been imported into the 2013-11 CF [1] and
marked "Needs Review". I looked at the version of the patch pointed to
in that CF entry back in July, and noted [2] several problems that
still seemed to be present in the patch, for which I never saw a
followup from Pavel. IMO this patch should have gotten marked
"Returned with Feedback" pending a response from Pavel.

That sounds reasonable to me. Perhaps you should so mark it.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#35Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#34)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/10/24 Robert Haas <robertmhaas@gmail.com>

On Tue, Oct 22, 2013 at 9:37 PM, Josh Kupershmidt <schmiddy@gmail.com>
wrote:

On Mon, Oct 14, 2013 at 5:38 PM, Josh Kupershmidt <schmiddy@gmail.com>

wrote:

Also, Pavel, this patch is still listed as 'Needs Review' in the CF
app, but I haven't seen a response to the concerns in my last message.

It looks like this patch has been imported into the 2013-11 CF [1] and
marked "Needs Review". I looked at the version of the patch pointed to
in that CF entry back in July, and noted [2] several problems that
still seemed to be present in the patch, for which I never saw a
followup from Pavel. IMO this patch should have gotten marked
"Returned with Feedback" pending a response from Pavel.

That sounds reasonable to me. Perhaps you should so mark it.

+1

Regards

Pavel

Show quoted text

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#36Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#32)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

[ catching up on old email ]

Andres Freund <andres@2ndquadrant.com> writes:

On 2013-10-15 00:23:15 +0200, Tomas Vondra wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

This thread seems to have gone cold, but I'm inclined to agree with
Pavel. If the table doesn't exist, neither does the trigger, and
the whole point of the 'IF EXISTS' variants is to provide the
ability to issue DROP commands that don't fail if their target is
missing.

-1, this seems to likely to just hide typos.

Because there simply is no reason to issue a DROP TRIGGER IF EXISTS if
you don't need the contents of the table. In that case you can just
issue a DROP TABLE IF EXISTS and start anew.

I think this is nonsense. It's only one step removed from "why do you
need IF EXISTS at all, you should know whether the object is there".
The entire point of this syntax is to not need to do detailed analysis
about whether the object is there.

The pg_dump --clean use-case is sufficient refutation for that, IMO.
You're suggesting that pg_dump should make a special case out of what it
emits for "cleaning" a trigger; which we could do I guess, but it would be
ugly and fragile. For instance, the special case would probably soon grow
some warts for partial-dump scenarios. Anyway, pg_dump is not the only tool
that might wish to use DROP IF EXISTS.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#37Andres Freund
andres@2ndquadrant.com
In reply to: Tom Lane (#36)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-11-10 16:28:27 -0500, Tom Lane wrote:

[ catching up on old email ]

Andres Freund <andres@2ndquadrant.com> writes:

On 2013-10-15 00:23:15 +0200, Tomas Vondra wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

This thread seems to have gone cold, but I'm inclined to agree with
Pavel. If the table doesn't exist, neither does the trigger, and
the whole point of the 'IF EXISTS' variants is to provide the
ability to issue DROP commands that don't fail if their target is
missing.

-1, this seems to likely to just hide typos.

Because there simply is no reason to issue a DROP TRIGGER IF EXISTS if
you don't need the contents of the table. In that case you can just
issue a DROP TABLE IF EXISTS and start anew.

I think this is nonsense. It's only one step removed from "why do you
need IF EXISTS at all, you should know whether the object is there".
The entire point of this syntax is to not need to do detailed analysis
about whether the object is there.

Well, in my opinion the IF EXISTS refers to the object type being
dropped. I.e. with DROP TABLE it refers to the table not existing, with
DROP TRIGGER it refers to the trigger not existing.
Note how we also error out if you do something like:
ALTER TABLE nonexistant DROP COLUMN IF EXISTS bar;

The pg_dump --clean use-case is sufficient refutation for that, IMO.
You're suggesting that pg_dump should make a special case out of what it
emits for "cleaning" a trigger; which we could do I guess, but it would be
ugly and fragile. For instance, the special case would probably soon grow
some warts for partial-dump scenarios.

ISTM the only way to get a DROP TRIGGER that actually is required is a
--section=post-data dump. In the other cases it will get dropped by the
DROP TABLE that's executed shortly afterwards. But in that case we'll
currently error out during the CREATE TRIGGER shortly afterwards if the
table doesn't exist...
Maybe the way to fix this properly is to not drop post-data objects that
are implicitly dropped by the object that owns them.

Anyway, pg_dump is not the only tool that might wish to use DROP IF EXISTS.

Well, I am absolutely not arguing against DROP TRIGGER IF NOT EXISTS
(which we already have), just against it ignoring nonexistant tables
instead of just nonexistant triggers.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#37)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Andres Freund <andres@2ndquadrant.com> writes:

On 2013-11-10 16:28:27 -0500, Tom Lane wrote:

I think this is nonsense. It's only one step removed from "why do you
need IF EXISTS at all, you should know whether the object is there".
The entire point of this syntax is to not need to do detailed analysis
about whether the object is there.

Well, in my opinion the IF EXISTS refers to the object type being
dropped. I.e. with DROP TABLE it refers to the table not existing, with
DROP TRIGGER it refers to the trigger not existing.

Then I take it you also think we should undo the changes that made
"DROP TABLE IF EXISTS foo.bar" not fail if schema foo doesn't exist?
Because after all, the schema is not the object being dropped.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39Andres Freund
andres@2ndquadrant.com
In reply to: Tom Lane (#38)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-11-10 18:16:16 -0500, Tom Lane wrote:

Andres Freund <andres@2ndquadrant.com> writes:

On 2013-11-10 16:28:27 -0500, Tom Lane wrote:

I think this is nonsense. It's only one step removed from "why do you
need IF EXISTS at all, you should know whether the object is there".
The entire point of this syntax is to not need to do detailed analysis
about whether the object is there.

Well, in my opinion the IF EXISTS refers to the object type being
dropped. I.e. with DROP TABLE it refers to the table not existing, with
DROP TRIGGER it refers to the trigger not existing.

Then I take it you also think we should undo the changes that made
"DROP TABLE IF EXISTS foo.bar" not fail if schema foo doesn't exist?
Because after all, the schema is not the object being dropped.

No, not the same thing imo, although I find that change debatable.

Anyway, if we're going to change DROP TRIGGER at the very least ALTER
TABLE ... DROP CONSTRAINT also needs to be changed, otherwise we'll gain
nothing.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#40Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#39)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Andres Freund <andres@2ndquadrant.com> writes:

On 2013-11-10 18:16:16 -0500, Tom Lane wrote:

Then I take it you also think we should undo the changes that made
"DROP TABLE IF EXISTS foo.bar" not fail if schema foo doesn't exist?
Because after all, the schema is not the object being dropped.

No, not the same thing imo, although I find that change debatable.

Anyway, if we're going to change DROP TRIGGER at the very least ALTER
TABLE ... DROP CONSTRAINT also needs to be changed, otherwise we'll gain
nothing.

That would be a plausible next step, but I don't have a problem with
this patch not solving every case like this at once.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#41Andres Freund
andres@2ndquadrant.com
In reply to: Tom Lane (#40)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-11-10 18:26:26 -0500, Tom Lane wrote:

Andres Freund <andres@2ndquadrant.com> writes:

On 2013-11-10 18:16:16 -0500, Tom Lane wrote:

Then I take it you also think we should undo the changes that made
"DROP TABLE IF EXISTS foo.bar" not fail if schema foo doesn't exist?
Because after all, the schema is not the object being dropped.

No, not the same thing imo, although I find that change debatable.

Anyway, if we're going to change DROP TRIGGER at the very least ALTER
TABLE ... DROP CONSTRAINT also needs to be changed, otherwise we'll gain
nothing.

That would be a plausible next step, but I don't have a problem with
this patch not solving every case like this at once.

Well, there are relatively few tables without primary keys around that
have triggers. The dumps currently look like:
DROP TRIGGER foo ON public.foo;
ALTER TABLE ONLY public.foo DROP CONSTRAINT foo_pkey;
ALTER TABLE public.foo ALTER COLUMN id DROP DEFAULT;
DROP SEQUENCE public.foo_id_seq;
DROP TABLE public.foo;
So we'd get approximately one line further unless we fix this for DROP
DEFAULT and DROP CONSTRAINT as well.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#42Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#41)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Andres Freund <andres@2ndquadrant.com> writes:

... So we'd get approximately one line further unless we fix this for DROP
DEFAULT and DROP CONSTRAINT as well.

True. As far as pg_dump --clean is concerned, it'd undoubtedly be easier
if we did what you suggest and just eliminate the emitted DROP commands
for table components, relying on the assumption that there'll never be
a partial-dump mode that would allow dumping a table's components without
the table. However, the server-side approach has the benefit that it'll
likely make life easier for other applications besides pg_dump.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#43Andres Freund
andres@2ndquadrant.com
In reply to: Tom Lane (#42)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-11-10 18:42:11 -0500, Tom Lane wrote:

Andres Freund <andres@2ndquadrant.com> writes:

... So we'd get approximately one line further unless we fix this for DROP
DEFAULT and DROP CONSTRAINT as well.

Turns out that's bogus - ALTER TABLE has two levels of NOT EXISTS.

Maybe we should just do the same for DROP TRIGGER?

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE | RESTRICT ]

However, the server-side approach has the benefit that it'll
likely make life easier for other applications besides pg_dump.

I am unconvinced that that's the case when using the existing IF EXISTS
for DROP TRIGGER, but my complaints would be completely addressed by
making it a separate flag.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#44Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#43)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Andres Freund <andres@2ndquadrant.com> writes:

Turns out that's bogus - ALTER TABLE has two levels of NOT EXISTS.

Maybe we should just do the same for DROP TRIGGER?

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE | RESTRICT ]

Works for me.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#45Pavel Stehule
pavel.stehule@gmail.com
In reply to: Andres Freund (#32)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

I can agree, so DROP TRIGGER doesn't need a IF EXISTS clause when it is
executed after DROP TABLE.

pg_dump -c produces:

DROP TRIGGER jjj ON public.foo;
DROP TABLE public.foo;
DROP FUNCTION public.f1();
DROP EXTENSION plpgsql;
DROP SCHEMA public;

Is there some reason why we use explicitly DROP TRIGGER there?

Regards

Pavel

2013/10/15 Andres Freund <andres@2ndquadrant.com>

Show quoted text

On 2013-10-15 00:23:15 +0200, Tomas Vondra wrote:

Hi,

On 14.10.2013 23:44, Andres Freund wrote:

On 2013-10-10 12:54:23 -0400, Andrew Dunstan wrote:

On 09/19/2013 06:12 PM, Pavel Stehule wrote:

2013/9/16 Satoshi Nagayasu <snaga@uptime.jp
<mailto:snaga@uptime.jp>>

I'm looking at this patch, and I have a question here.

Should "DROP TRIGGER IF EXISTS" ignore error for non-existing
trigger and non-existing table? Or just only for non-existing
trigger?

My opinion is so, both variants should be ignored - it should be
fully fault tolerant in this use case.

This thread seems to have gone cold, but I'm inclined to agree with
Pavel. If the table doesn't exist, neither does the trigger, and
the whole point of the 'IF EXISTS' variants is to provide the
ability to issue DROP commands that don't fail if their target is
missing.

-1, this seems to likely to just hide typos.

Not sure I agree with your reasoning. Isn't that equally true for 'IF
EXISTS' clause with all commands in general? Why should we use "likely
to hide typos" argument in this case and not the others?

Because there simply is no reason to issue a DROP TRIGGER IF EXISTS if
you don't need the contents of the table. In that case you can just
issue a DROP TABLE IF EXISTS and start anew.

The purpose of this patch was to add support for quiet "pg_restore
--clean" and pg_restore should not do typos (if it does, we're in much
deeper troubles I guess).

Why does that even have to do anything for triggers? Emitting DROP TABLE
should be enough.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#46Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#44)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/11/11 Tom Lane <tgl@sss.pgh.pa.us>

Andres Freund <andres@2ndquadrant.com> writes:

Turns out that's bogus - ALTER TABLE has two levels of NOT EXISTS.

Maybe we should just do the same for DROP TRIGGER?

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE |

RESTRICT ]

Works for me.

for me too

tomorrow I'll prepare patch

Regards

Pavel

Show quoted text

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#47Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#46)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/11/11 Pavel Stehule <pavel.stehule@gmail.com>

2013/11/11 Tom Lane <tgl@sss.pgh.pa.us>

Andres Freund <andres@2ndquadrant.com> writes:

Turns out that's bogus - ALTER TABLE has two levels of NOT EXISTS.

Maybe we should just do the same for DROP TRIGGER?

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE |

RESTRICT ]

This syntax is not consistent with other IF EXISTS.

should be (IF EXISTS is before name always)

DROP TRIGGER [ IF EXISTS ] name ON [ IF EXISTS ] table_name [ CASCADE |
RESTRICT ]

What do you think about?

Regards

Pavel

Show quoted text

Works for me.

for me too

tomorrow I'll prepare patch

Regards

Pavel

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#48Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#46)
1 attachment(s)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

here is patch with fault tolerant drop trigger and drop rule support

drop trigger [if exists] trgname on [if exists] tablename;
drop rule [if exists] trgname on [if exists] tablename;

Regards

Pavel

2013/11/11 Pavel Stehule <pavel.stehule@gmail.com>

Show quoted text

2013/11/11 Tom Lane <tgl@sss.pgh.pa.us>

Andres Freund <andres@2ndquadrant.com> writes:

Turns out that's bogus - ALTER TABLE has two levels of NOT EXISTS.

Maybe we should just do the same for DROP TRIGGER?

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE |

RESTRICT ]

Works for me.

for me too

tomorrow I'll prepare patch

Regards

Pavel

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Attachments:

drop-trigger.patchtext/x-patch; charset=US-ASCII; name=drop-trigger.patchDownload
diff --git a/doc/src/sgml/ref/drop_rule.sgml b/doc/src/sgml/ref/drop_rule.sgml
index c845872..585f67b 100644
--- a/doc/src/sgml/ref/drop_rule.sgml
+++ b/doc/src/sgml/ref/drop_rule.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-DROP RULE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
+DROP RULE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON [ IF EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -42,8 +42,8 @@ DROP RULE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON <re
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the rule does not exist. A notice is issued
-      in this case.
+      Do not throw an error if the rule does not exist (or if a parent table
+      does not exist). A notice is issued in this case.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/drop_trigger.sgml b/doc/src/sgml/ref/drop_trigger.sgml
index 3ec6cc7..1f46eff 100644
--- a/doc/src/sgml/ref/drop_trigger.sgml
+++ b/doc/src/sgml/ref/drop_trigger.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
+DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON  [ IF EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -44,8 +44,8 @@ DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the trigger does not exist. A notice is issued
-      in this case.
+      Do not throw an error if the trigger does not exist (or parent table
+      does not exist). A notice is issued in this case.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index cecddf1..36ef9ae 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -423,7 +423,8 @@ static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
 							   List *objname, Relation *relp,
 							   LOCKMODE lockmode, bool missing_ok);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp, bool missing_ok);
+							 List *objname, Relation *relp,
+							 bool missing_ok, bool missing_parent_ok);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
 							 List *objname, Relation *relp,
 							 LOCKMODE lockmode, bool missing_ok);
@@ -464,7 +465,8 @@ static void getRelationIdentity(StringInfo buffer, Oid relid);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
+				   Relation *relp, LOCKMODE lockmode,
+				   bool missing_ok, bool missing_parent_ok)
 {
 	ObjectAddress address;
 	ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
@@ -507,7 +509,9 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			case OBJECT_TRIGGER:
 			case OBJECT_CONSTRAINT:
 				address = get_object_address_relobject(objtype, objname,
-													   &relation, missing_ok);
+													   &relation,
+													   missing_ok,
+													   missing_parent_ok);
 				break;
 			case OBJECT_DATABASE:
 			case OBJECT_EXTENSION:
@@ -622,7 +626,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		 */
 		if (!OidIsValid(address.objectId))
 		{
-			Assert(missing_ok);
+			Assert(missing_ok || missing_parent_ok);
 			return address;
 		}
 
@@ -898,7 +902,9 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  */
 static ObjectAddress
 get_object_address_relobject(ObjectType objtype, List *objname,
-							 Relation *relp, bool missing_ok)
+							 Relation *relp,
+								 bool missing_ok,
+								 bool missing_parent_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -942,42 +948,55 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_parent_ok);
 
-		switch (objtype)
+		if (relation != NULL)
 		{
-			case OBJECT_RULE:
-				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
-				address.objectSubId = 0;
-				break;
-			case OBJECT_TRIGGER:
-				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
-				address.objectSubId = 0;
-				break;
-			case OBJECT_CONSTRAINT:
-				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
-				address.objectSubId = 0;
-				break;
-			default:
-				elog(ERROR, "unrecognized objtype: %d", (int) objtype);
-				/* placate compiler, which doesn't know elog won't return */
-				address.classId = InvalidOid;
-				address.objectId = InvalidOid;
-				address.objectSubId = 0;
-		}
+			reloid = RelationGetRelid(relation);
 
-		/* Avoid relcache leak when object not found. */
-		if (!OidIsValid(address.objectId))
+			switch (objtype)
+			{
+				case OBJECT_RULE:
+					address.classId = RewriteRelationId;
+					address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+					address.objectSubId = 0;
+					break;
+				case OBJECT_TRIGGER:
+					address.classId = TriggerRelationId;
+					address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+					address.objectSubId = 0;
+					break;
+				case OBJECT_CONSTRAINT:
+					address.classId = ConstraintRelationId;
+					address.objectId =
+						get_relation_constraint_oid(reloid, depname, missing_ok);
+					address.objectSubId = 0;
+					break;
+				default:
+					elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+					/* placate compiler, which doesn't know elog won't return */
+					address.classId = InvalidOid;
+					address.objectId = InvalidOid;
+					address.objectSubId = 0;
+			}
+
+			/* Avoid relcache leak when object not found. */
+			if (!OidIsValid(address.objectId))
+			{
+				heap_close(relation, AccessShareLock);
+				relation = NULL;	/* department of accident prevention */
+				return address;
+			}
+		}
+		else
 		{
-			heap_close(relation, AccessShareLock);
-			relation = NULL;	/* department of accident prevention */
-			return address;
+			Assert(missing_parent_ok);
+
+			address.classId = InvalidOid;
+			address.objectId = InvalidOid;
+			address.objectSubId = 0;
 		}
 	}
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index b62ec70..04e1481 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -364,7 +364,8 @@ ExecRenameStmt(RenameStmt *stmt)
 				address = get_object_address(stmt->renameType,
 											 stmt->object, stmt->objarg,
 											 &relation,
-											 AccessExclusiveLock, false);
+											 AccessExclusiveLock,
+											 false, false);
 				Assert(relation == NULL);
 
 				catalog = heap_open(address.classId, RowExclusiveLock);
@@ -431,6 +432,7 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
 											 stmt->objarg,
 											 &relation,
 											 AccessExclusiveLock,
+											 false,
 											 false);
 				Assert(relation == NULL);
 				classId = address.classId;
@@ -725,6 +727,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
 											 stmt->objarg,
 											 &relation,
 											 AccessExclusiveLock,
+											 false,
 											 false);
 				Assert(relation == NULL);
 				classId = address.classId;
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 5ecc92a..5b77e87 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -71,7 +71,8 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock, false);
+								 &relation, ShareUpdateExclusiveLock,
+								 false, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..4529727 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -31,6 +31,8 @@
 
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
+static void parent_not_exists_skipping(ObjectType objtype,
+						List *objname);
 
 /*
  * Drop one or more objects.
@@ -71,12 +73,17 @@ RemoveObjects(DropStmt *stmt)
 									 objname, objargs,
 									 &relation,
 									 AccessExclusiveLock,
-									 stmt->missing_ok);
+									 stmt->missing_ok,
+									 stmt->missing_parent_ok);
 
 		/* Issue NOTICE if supplied object was not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			does_not_exist_skipping(stmt->removeType, objname, objargs);
+			/* ObjectId can be invalid due missing parent relation */
+			if (stmt->missing_parent_ok && !OidIsValid(address.classId))
+				parent_not_exists_skipping(stmt->removeType, objname);
+			else
+				does_not_exist_skipping(stmt->removeType, objname, objargs);
 			continue;
 		}
 
@@ -244,3 +251,25 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 	else
 		ereport(NOTICE, (errmsg(msg, name, args)));
 }
+
+/*
+ * Generate a NOTICE "table does not exists, skipping". It is used when
+ * clause IF EXISTS is twice used.
+ */
+static void
+parent_not_exists_skipping(ObjectType objtype, List *objname)
+{
+	switch (objtype)
+	{
+		case OBJECT_RULE:
+		case OBJECT_TRIGGER:
+			ereport(NOTICE,
+				 (errmsg("table \%s\" does not exists, skipping",
+					NameListToString(list_truncate(list_copy(objname),
+							  list_length(objname) - 1)))));
+			break;
+		default:
+			elog(ERROR, "unexpected object type (%d)", (int) objtype);
+			break;
+	}
+}
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 798c92a..83a6d92 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2908,7 +2908,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock, false);
+								&relation, ShareUpdateExclusiveLock,
+								false, false);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index eaf0d0d..115c395 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,8 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock, false);
+								 &relation, ShareUpdateExclusiveLock,
+								 false, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1733da6..a8c5b85 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2798,6 +2798,7 @@ _copyDropStmt(const DropStmt *from)
 	COPY_SCALAR_FIELD(removeType);
 	COPY_SCALAR_FIELD(behavior);
 	COPY_SCALAR_FIELD(missing_ok);
+	COPY_SCALAR_FIELD(missing_parent_ok);
 	COPY_SCALAR_FIELD(concurrent);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7b29812..7fe85fb 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1137,6 +1137,7 @@ _equalDropStmt(const DropStmt *a, const DropStmt *b)
 	COMPARE_SCALAR_FIELD(removeType);
 	COMPARE_SCALAR_FIELD(behavior);
 	COMPARE_SCALAR_FIELD(missing_ok);
+	COMPARE_SCALAR_FIELD(missing_parent_ok);
 	COMPARE_SCALAR_FIELD(concurrent);
 
 	return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 8dc4b1c..2fb9388 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3546,6 +3546,7 @@ DropPLangStmt:
 					n->arguments = NIL;
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -3556,6 +3557,7 @@ DropPLangStmt:
 					n->objects = list_make1(list_make1(makeString($6)));
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -3969,6 +3971,7 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($5)));
 					n->arguments = NIL;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->behavior = $6;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -3980,6 +3983,7 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($7)));
 					n->arguments = NIL;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->behavior = $8;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -4131,6 +4135,7 @@ DropForeignServerStmt: DROP SERVER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($3)));
 					n->arguments = NIL;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->behavior = $4;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -4142,6 +4147,7 @@ DropForeignServerStmt: DROP SERVER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($5)));
 					n->arguments = NIL;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->behavior = $6;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -4512,6 +4518,7 @@ DropTrigStmt:
 					n->arguments = NIL;
 					n->behavior = $6;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -4523,6 +4530,31 @@ DropTrigStmt:
 					n->arguments = NIL;
 					n->behavior = $8;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP TRIGGER name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_TRIGGER;
+					n->objects = list_make1(lappend($7, makeString($3)));
+					n->arguments = NIL;
+					n->behavior = $8;
+					n->missing_ok = false;
+					n->missing_parent_ok = true;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP TRIGGER IF_P EXISTS name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_TRIGGER;
+					n->objects = list_make1(lappend($9, makeString($5)));
+					n->arguments = NIL;
+					n->behavior = $10;
+					n->missing_ok = true;
+					n->missing_parent_ok = true;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5055,6 +5087,7 @@ DropOpClassStmt:
 					n->removeType = OBJECT_OPCLASS;
 					n->behavior = $7;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5066,6 +5099,7 @@ DropOpClassStmt:
 					n->removeType = OBJECT_OPCLASS;
 					n->behavior = $9;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5080,6 +5114,7 @@ DropOpFamilyStmt:
 					n->removeType = OBJECT_OPFAMILY;
 					n->behavior = $7;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5091,6 +5126,7 @@ DropOpFamilyStmt:
 					n->removeType = OBJECT_OPFAMILY;
 					n->behavior = $9;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5139,6 +5175,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
 					n->missing_ok = TRUE;
+					n->missing_parent_ok = false;
 					n->objects = $5;
 					n->arguments = NIL;
 					n->behavior = $6;
@@ -5150,6 +5187,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
 					n->missing_ok = FALSE;
+					n->missing_parent_ok = false;
 					n->objects = $3;
 					n->arguments = NIL;
 					n->behavior = $4;
@@ -5161,6 +5199,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_INDEX;
 					n->missing_ok = FALSE;
+					n->missing_parent_ok = false;
 					n->objects = $4;
 					n->arguments = NIL;
 					n->behavior = $5;
@@ -5172,6 +5211,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_INDEX;
 					n->missing_ok = TRUE;
+					n->missing_parent_ok = false;
 					n->objects = $6;
 					n->arguments = NIL;
 					n->behavior = $7;
@@ -6635,6 +6675,7 @@ RemoveFuncStmt:
 					n->arguments = list_make1(extractArgTypes($4));
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6646,6 +6687,7 @@ RemoveFuncStmt:
 					n->arguments = list_make1(extractArgTypes($6));
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6660,6 +6702,7 @@ RemoveAggrStmt:
 					n->arguments = list_make1(extractArgTypes($4));
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6671,6 +6714,7 @@ RemoveAggrStmt:
 					n->arguments = list_make1(extractArgTypes($6));
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6685,6 +6729,7 @@ RemoveOperStmt:
 					n->arguments = list_make1($4);
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6696,6 +6741,7 @@ RemoveOperStmt:
 					n->arguments = list_make1($6);
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6813,6 +6859,7 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha
 					n->arguments = list_make1(list_make1($7));
 					n->behavior = $9;
 					n->missing_ok = $3;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -7821,6 +7868,7 @@ DropRuleStmt:
 					n->arguments = NIL;
 					n->behavior = $6;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -7832,6 +7880,31 @@ DropRuleStmt:
 					n->arguments = NIL;
 					n->behavior = $8;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP RULE name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_RULE;
+					n->objects = list_make1(lappend($7, makeString($3)));
+					n->arguments = NIL;
+					n->behavior = $8;
+					n->missing_ok = false;
+					n->missing_parent_ok = true;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP RULE IF_P EXISTS name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_RULE;
+					n->objects = list_make1(lappend($9, makeString($5)));
+					n->arguments = NIL;
+					n->behavior = $10;
+					n->missing_ok = true;
+					n->missing_parent_ok = true;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index e2a5b0d..05f20ff 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -30,7 +30,8 @@ typedef struct ObjectAddress
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
 				   List *objargs, Relation *relp,
-				   LOCKMODE lockmode, bool missing_ok);
+				   LOCKMODE lockmode,
+				   bool missing_ok, bool missing_parent_ok);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 952fbb3..57178bd 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2003,6 +2003,7 @@ typedef struct DropStmt
 	ObjectType	removeType;		/* object type */
 	DropBehavior behavior;		/* RESTRICT or CASCADE behavior */
 	bool		missing_ok;		/* skip error if object is missing? */
+	bool		missing_parent_ok;	/* skip error if parent is missing? */
 	bool		concurrent;		/* drop index concurrently? */
 } DropStmt;
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 62fc7c5..c688999 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2630,3 +2630,10 @@ ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renam
 ERROR:  renaming an ON SELECT rule is not allowed
 DROP VIEW rule_v1;
 DROP TABLE rule_t1;
+--
+-- fault tolerant drop rule
+--
+DROP RULE IF EXISTS noexistname ON IF EXISTS noexistname;
+NOTICE:  table noexistname" does not exists, skipping
+DROP RULE noexistname ON IF EXISTS noexistname;
+NOTICE:  table noexistname" does not exists, skipping
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 6a6ecf7..35622cc 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -1731,3 +1731,8 @@ select * from self_ref_trigger;
 drop table self_ref_trigger;
 drop function self_ref_trigger_ins_func();
 drop function self_ref_trigger_del_func();
+-- fault tolerant trigger
+drop trigger not_exists_trigger on if exists not_exists_table;
+NOTICE:  table not_exists_table" does not exists, skipping
+drop trigger if exists not_exists_trigger on if exists not_exists_table;
+NOTICE:  table not_exists_table" does not exists, skipping
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index 1e15f84..23e9423 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -1007,3 +1007,9 @@ ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renam
 
 DROP VIEW rule_v1;
 DROP TABLE rule_t1;
+
+--
+-- fault tolerant drop rule
+--
+DROP RULE IF EXISTS noexistname ON IF EXISTS noexistname;
+DROP RULE noexistname ON IF EXISTS noexistname;
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 0ea2c31..6174f95 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -1173,3 +1173,7 @@ select * from self_ref_trigger;
 drop table self_ref_trigger;
 drop function self_ref_trigger_ins_func();
 drop function self_ref_trigger_del_func();
+
+-- fault tolerant trigger
+drop trigger not_exists_trigger on if exists not_exists_table;
+drop trigger if exists not_exists_trigger on if exists not_exists_table;
#49Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Pavel Stehule (#48)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 12 November 2013 16:00, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hello

here is patch with fault tolerant drop trigger and drop rule support

drop trigger [if exists] trgname on [if exists] tablename;
drop rule [if exists] trgname on [if exists] tablename;

Regards

Pavel

Hi,

I have just started looking at this patch.

It applies cleanly to head, and appears to work as intended. I have a
question though about the syntax. Looking back over this thread, there
seem to have been 3 different possibilities discussed:

1). Keep the existing syntax:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

but make it tolerate a non-existent table when "IF EXISTS" is specified.

2). Support 2 independent levels of "IF EXISTS" using the syntax:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE
| RESTRICT ]

There was some consensus for this, but then Pavel pointed out that it
is inconsistent with other DROP commands, which all have the "IF
EXISTS" before the object to which it refers.

3). Support 2 independent levels of "IF EXISTS" using the syntax:

DROP TRIGGER [ IF EXISTS ] name ON [ IF EXISTS ] table_name [ CASCADE
| RESTRICT ]

which is what the latest patch does.

The syntax in option (3) is certainly more consistent with other DROP
commands, but it feels pretty clunky from a grammar point-of-view. It
also feels overly complex for the use cases discussed.

Personally I would prefer option (1). The SQL standard syntax is
simply "DROP TRIGGER name". The only reason we have the "ON
table_name" part is that our trigger names aren't globally unique, so
"trigger_name ON table_name" is required to uniquely identify the
trigger to drop, which would seem to be directly analogous to
specifying a schema in DROP TABLE, and we've already made that
tolerate a non-existent schema if "IF EXISTS" is used.

This seems rather different from ALTER TABLE, which allows multiple
sub-commands on the same table, so naturally lends itself to multiple
independent DROP <objtype> [IF EXISTS] sub-commands underneath the
top-level ALTER TABLE [IF EXISTS], for example:

ALTER TABLE IF EXISTS table_name
DROP COLUMN IF EXISTS col_name,
DROP CONSTRAINT IF EXISTS constr_name;

So what we currently have can be summarised as 2 classes of
commands/sub-commands to which "IF EXISTS" applies:

ALTER <objtype> [IF EXISTS] ...
DROP <objtype> [IF EXISTS] ...

We don't yet have multiple levels of "IF EXISTS" within the same DROP,
and I don't think it is necessary. For example, no one seems to be
asking for

DROP TABLE [IF EXISTS] table_name IN [IF EXISTS] schema_name

Anyway, that's just my opinion. Clearly there is at least one person
with a different opinion. What do other people think?

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#50Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#49)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

I am thinking so @2 is not good idea. Using well known idiom "IF EXISTS"
once before table name and second after table name can be difficult and
messy for users. If you like it, use different idiom or different keyword,
please.

My person favourite is @1 - fault tolerant version - but I understand to
objection (what was reason, why I wrote a last version @3) - @1 and @3 are
good decision.

Regards

Pavel

2013/11/19 Dean Rasheed <dean.a.rasheed@gmail.com>

Show quoted text

On 12 November 2013 16:00, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hello

here is patch with fault tolerant drop trigger and drop rule support

drop trigger [if exists] trgname on [if exists] tablename;
drop rule [if exists] trgname on [if exists] tablename;

Regards

Pavel

Hi,

I have just started looking at this patch.

It applies cleanly to head, and appears to work as intended. I have a
question though about the syntax. Looking back over this thread, there
seem to have been 3 different possibilities discussed:

1). Keep the existing syntax:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

but make it tolerate a non-existent table when "IF EXISTS" is specified.

2). Support 2 independent levels of "IF EXISTS" using the syntax:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE
| RESTRICT ]

There was some consensus for this, but then Pavel pointed out that it
is inconsistent with other DROP commands, which all have the "IF
EXISTS" before the object to which it refers.

3). Support 2 independent levels of "IF EXISTS" using the syntax:

DROP TRIGGER [ IF EXISTS ] name ON [ IF EXISTS ] table_name [ CASCADE
| RESTRICT ]

which is what the latest patch does.

The syntax in option (3) is certainly more consistent with other DROP
commands, but it feels pretty clunky from a grammar point-of-view. It
also feels overly complex for the use cases discussed.

Personally I would prefer option (1). The SQL standard syntax is
simply "DROP TRIGGER name". The only reason we have the "ON
table_name" part is that our trigger names aren't globally unique, so
"trigger_name ON table_name" is required to uniquely identify the
trigger to drop, which would seem to be directly analogous to
specifying a schema in DROP TABLE, and we've already made that
tolerate a non-existent schema if "IF EXISTS" is used.

This seems rather different from ALTER TABLE, which allows multiple
sub-commands on the same table, so naturally lends itself to multiple
independent DROP <objtype> [IF EXISTS] sub-commands underneath the
top-level ALTER TABLE [IF EXISTS], for example:

ALTER TABLE IF EXISTS table_name
DROP COLUMN IF EXISTS col_name,
DROP CONSTRAINT IF EXISTS constr_name;

So what we currently have can be summarised as 2 classes of
commands/sub-commands to which "IF EXISTS" applies:

ALTER <objtype> [IF EXISTS] ...
DROP <objtype> [IF EXISTS] ...

We don't yet have multiple levels of "IF EXISTS" within the same DROP,
and I don't think it is necessary. For example, no one seems to be
asking for

DROP TABLE [IF EXISTS] table_name IN [IF EXISTS] schema_name

Anyway, that's just my opinion. Clearly there is at least one person
with a different opinion. What do other people think?

Regards,
Dean

#51Robert Haas
robertmhaas@gmail.com
In reply to: Dean Rasheed (#49)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Tue, Nov 19, 2013 at 3:53 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:

1). Keep the existing syntax:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

but make it tolerate a non-existent table when "IF EXISTS" is specified.

I don't love this option, but I like it better than the other proposals.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#52Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#51)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/11/19 Robert Haas <robertmhaas@gmail.com>

On Tue, Nov 19, 2013 at 3:53 AM, Dean Rasheed <dean.a.rasheed@gmail.com>
wrote:

1). Keep the existing syntax:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

but make it tolerate a non-existent table when "IF EXISTS" is specified.

I don't love this option, but I like it better than the other proposals.

we are in agreement, so we want this feature. How we can decide about
syntax?

I am feeling, so almost all people prefer

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

Can we live with it?

Regards

Pavel

Show quoted text

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#53Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#52)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 11/21/13, 2:35 AM, Pavel Stehule wrote:

I am feeling, so almost all people prefer

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

Can we live with it?

Fine with me.

I think it helps if you consider IF EXISTS an attribute of the command,
not an attribute of the command parameters.

Now we should be aware that this sort of sets a precedent for ALTER
TABLE IF EXISTS ... DROP ANYTHING ... and similar composite commands.

If might be worth checking other SQL databases. We stole the IF EXISTS
from somewhere, I believe.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#54Andres Freund
andres@2ndquadrant.com
In reply to: Peter Eisentraut (#53)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2013-11-21 17:14:17 -0500, Peter Eisentraut wrote:

On 11/21/13, 2:35 AM, Pavel Stehule wrote:

I am feeling, so almost all people prefer

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

Can we live with it?

Fine with me.

I think it helps if you consider IF EXISTS an attribute of the command,
not an attribute of the command parameters.

Now we should be aware that this sort of sets a precedent for ALTER
TABLE IF EXISTS ... DROP ANYTHING ... and similar composite commands.

That already has 2 independent IF EXISTS, so I think the precedence
argument goes the other way round.

Greetings,

Andres Freund

--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#55Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#53)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/11/21 Peter Eisentraut <peter_e@gmx.net>

On 11/21/13, 2:35 AM, Pavel Stehule wrote:

I am feeling, so almost all people prefer

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ];

Can we live with it?

Fine with me.

I think it helps if you consider IF EXISTS an attribute of the command,
not an attribute of the command parameters.

Now we should be aware that this sort of sets a precedent for ALTER
TABLE IF EXISTS ... DROP ANYTHING ... and similar composite commands.

If might be worth checking other SQL databases. We stole the IF EXISTS
from somewhere, I believe.

I did some searching:

So DROP TRIGGER IF EXISTS is supported by

SQL anywhere, MySQL

Doesn't support:

MS SQL server (conditional drops is by T-SQL IF EXISTS() statement),
Oracle, DB2,

But significant difference between PostgreSQL and other databases is
requirement to specify table in DROP statement. So in SQL anywhere or in
MySQL DROP TRIGGER IF EXISTS is fully fault tolerant, there are not
possibility to specify table.

Note: DROP TRIGGER ON tablename is PostgreSQL feature - no other databases
(without PostgreSQL forks) uses this syntax - so we don't need thinking
what is in (or what will be) in ANSI standard (or what other databases
does). In this moment syntax of DROP TRIGGER is non standard. So if we can
adopt design (idea) in SQL anywhere or MySQL, then DROP TRIGGER IF EXISTS
should be enough. In our implementation there are two conditions, but we
should not to check if target table exists (from statement purpose).

So now, +1 for using "DROP TRIGGER IF EXISTS name ON tablename" without
requirement for tablename

Regards

Pavel

#56Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#55)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 11/24/13, 2:28 PM, Pavel Stehule wrote:

Note: DROP TRIGGER ON tablename is PostgreSQL feature - no other
databases (without PostgreSQL forks) uses this syntax - so we don't need
thinking what is in (or what will be) in ANSI standard (or what other
databases does). In this moment syntax of DROP TRIGGER is non standard.
So if we can adopt design (idea) in SQL anywhere or MySQL, then DROP
TRIGGER IF EXISTS should be enough. In our implementation there are two
conditions, but we should not to check if target table exists (from
statement purpose).

Right, we might as well consider 'trigger ON tablename' to be the full
name of the trigger and just treat it like a unit.

But then a single IF EXISTS clause is still inconsistent with DROP TABLE
nonexistent.foo, which fails if the schema does not exist. In other
words, the IF EXISTS clause only applies to the end of an name chain.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#57Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Peter Eisentraut (#56)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 26 November 2013 19:54, Peter Eisentraut <peter_e@gmx.net> wrote:

On 11/24/13, 2:28 PM, Pavel Stehule wrote:

Note: DROP TRIGGER ON tablename is PostgreSQL feature - no other
databases (without PostgreSQL forks) uses this syntax - so we don't need
thinking what is in (or what will be) in ANSI standard (or what other
databases does). In this moment syntax of DROP TRIGGER is non standard.
So if we can adopt design (idea) in SQL anywhere or MySQL, then DROP
TRIGGER IF EXISTS should be enough. In our implementation there are two
conditions, but we should not to check if target table exists (from
statement purpose).

Right, we might as well consider 'trigger ON tablename' to be the full
name of the trigger and just treat it like a unit.

Yeah, that's how I would view it.

But then a single IF EXISTS clause is still inconsistent with DROP TABLE
nonexistent.foo, which fails if the schema does not exist. In other
words, the IF EXISTS clause only applies to the end of an name chain.

Actually the IF EXISTS in DROP TABLE now applies to the schema as
well. Unfortunately there is currently no consistency across the
various DROP commands --- some tolerate a non-existent schema, while
others error out. Also amongst those that tolerate a non-existent
schema, the resulting notices are not consistent --- some report the
schema-qualified object name, while others just report the local
object name.

Here is the current state of HEAD:

DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
ERROR: schema "no_such_schema" does not exist

DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
ERROR: schema "no_such_schema" does not exist

DROP COLLATION IF EXISTS no_such_schema.foo;
NOTICE: collation "no_such_schema.foo" does not exist, skipping
DROP COLLATION

DROP CONVERSION IF EXISTS no_such_schema.foo;
NOTICE: conversion "no_such_schema.foo" does not exist, skipping
DROP CONVERSION

DROP DOMAIN IF EXISTS no_such_schema.foo;
ERROR: schema "no_such_schema" does not exist

DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
NOTICE: foreign table "foo" does not exist, skipping
DROP FOREIGN TABLE

DROP FUNCTION IF EXISTS no_such_schema.foo();
ERROR: schema "no_such_schema" does not exist

DROP INDEX IF EXISTS no_such_schema.foo;
NOTICE: index "foo" does not exist, skipping
DROP INDEX

DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
NOTICE: materialized view "foo" does not exist, skipping
DROP MATERIALIZED VIEW

DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
ERROR: schema "no_such_schema" does not exist

DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
ERROR: schema "no_such_schema" does not exist

DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
ERROR: schema "no_such_schema" does not exist

DROP RULE IF EXISTS foo ON no_such_schema.bar;
ERROR: schema "no_such_schema" does not exist

DROP SEQUENCE IF EXISTS no_such_schema.foo;
NOTICE: sequence "foo" does not exist, skipping
DROP SEQUENCE

DROP TABLE IF EXISTS no_such_schema.foo;
NOTICE: table "foo" does not exist, skipping
DROP TABLE

DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
NOTICE: text search configuration "no_such_schema.foo" does not exist, skipping
DROP TEXT SEARCH CONFIGURATION

DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
NOTICE: text search dictionary "no_such_schema.foo" does not exist, skipping
DROP TEXT SEARCH DICTIONARY

DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
NOTICE: text search parser "no_such_schema.foo" does not exist, skipping
DROP TEXT SEARCH PARSER

DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
NOTICE: text search template "no_such_schema.foo" does not exist, skipping
DROP TEXT SEARCH TEMPLATE

DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
ERROR: schema "no_such_schema" does not exist

DROP TYPE IF EXISTS no_such_schema.foo;
ERROR: schema "no_such_schema" does not exist

DROP VIEW IF EXISTS no_such_schema.foo;
NOTICE: view "foo" does not exist, skipping
DROP VIEW

That's a lot of inconsistency --- 10 errors vs 12 notices (6 with
schema-qualified names and 6 with only local names).

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#58Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dean Rasheed (#57)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Dean Rasheed <dean.a.rasheed@gmail.com> writes:

Actually the IF EXISTS in DROP TABLE now applies to the schema as
well. Unfortunately there is currently no consistency across the
various DROP commands --- some tolerate a non-existent schema, while
others error out.

Yeah. I think now that we've had this discussion, we should make them
all tolerate a non-existent schema. I'm fine with having that happen
over a series of patches rather than all at once though.

Also amongst those that tolerate a non-existent
schema, the resulting notices are not consistent --- some report the
schema-qualified object name, while others just report the local
object name.

Less excited about this part, but on the whole I'd vote for the "schema
"no_such_schema" does not exist" wording in cases where the schema isn't
there. The other way is less specific for no very good reason.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#59Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#58)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

I'll prepare patch

2013/11/27 Tom Lane <tgl@sss.pgh.pa.us>

Show quoted text

Dean Rasheed <dean.a.rasheed@gmail.com> writes:

Actually the IF EXISTS in DROP TABLE now applies to the schema as
well. Unfortunately there is currently no consistency across the
various DROP commands --- some tolerate a non-existent schema, while
others error out.

Yeah. I think now that we've had this discussion, we should make them
all tolerate a non-existent schema. I'm fine with having that happen
over a series of patches rather than all at once though.

Also amongst those that tolerate a non-existent
schema, the resulting notices are not consistent --- some report the
schema-qualified object name, while others just report the local
object name.

Less excited about this part, but on the whole I'd vote for the "schema
"no_such_schema" does not exist" wording in cases where the schema isn't
there. The other way is less specific for no very good reason.

regards, tom lane

#60Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#58)
1 attachment(s)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/11/27 Tom Lane <tgl@sss.pgh.pa.us>

Dean Rasheed <dean.a.rasheed@gmail.com> writes:

Actually the IF EXISTS in DROP TABLE now applies to the schema as
well. Unfortunately there is currently no consistency across the
various DROP commands --- some tolerate a non-existent schema, while
others error out.

Yeah. I think now that we've had this discussion, we should make them
all tolerate a non-existent schema. I'm fine with having that happen
over a series of patches rather than all at once though.

Also amongst those that tolerate a non-existent
schema, the resulting notices are not consistent --- some report the
schema-qualified object name, while others just report the local
object name.

Less excited about this part, but on the whole I'd vote for the "schema
"no_such_schema" does not exist" wording in cases where the schema isn't
there. The other way is less specific for no very good reason.

can be used this behave (see attached patch, please)?

if it is correct, I'll work on second patch, that unify check and notices
for other DROP IF EXISTS statements.

Regards

Pavel

Show quoted text

regards, tom lane

Attachments:

drop-trigger-if-exists.patchtext/x-patch; charset=US-ASCII; name=drop-trigger-if-exists.patchDownload
commit a2de2b402247fded7feba90bf299e91ee14aacca
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Thu Nov 28 08:39:43 2013 +0100

    initial

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 9011190..234673f 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -942,26 +942,30 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_ok);
+
+		reloid = (relation != NULL) ? RelationGetRelid(relation) : InvalidOid;
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			default:
@@ -975,7 +979,9 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 		/* Avoid relcache leak when object not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			heap_close(relation, AccessShareLock);
+			if (relation != NULL)
+				heap_close(relation, AccessShareLock);
+
 			relation = NULL;	/* department of accident prevention */
 			return address;
 		}
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..191aa17 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -23,6 +23,7 @@
 #include "catalog/pg_class.h"
 #include "catalog/pg_proc.h"
 #include "commands/defrem.h"
+#include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "parser/parse_type.h"
@@ -32,6 +33,12 @@
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
 
+static void prepare_notice_recheck_parent(const char *message,
+						List *objname,
+								const char **msg,
+								char **name,
+								char **args);
+
 /*
  * Drop one or more objects.
  *
@@ -125,6 +132,53 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * Prepare text of "does not exist, skipping" message for triggers and rules,
+ * where we check schema name first, then table name, and as last we raise
+ * message about missing object.
+ */
+static void
+prepare_notice_recheck_parent(const char *message, List *objname,
+							const char **msg,
+							char **name,
+							char **args)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(list_truncate(list_copy(objname),
+							list_length(objname) - 1));
+
+	if (rel->schemaname != NULL && !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exists, skipping");
+		*name = rel->schemaname;
+		*args = NULL;
+	}
+	else if (!OidIsValid(RangeVarGetRelid(rel, NoLock, true)))
+	{
+		*msg = gettext_noop("relation \"%s\" does not exists, skipping");
+		*name = rel->relname;
+		*args = NULL;
+	}
+	else
+	{
+		StringInfoData string;
+
+		*msg = message;
+		*name = strVal(llast(objname));
+
+		initStringInfo(&string);
+		if (rel->schemaname != NULL)
+		{
+			appendStringInfoString(&string, rel->schemaname);
+			appendStringInfoChar(&string, '.');
+		}
+		appendStringInfoString(&string, rel->relname);
+
+		*args = string.data;
+	}
+}
+
+/*
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
  * get_object_address() will throw an ERROR.
@@ -201,20 +255,18 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 											(TypeName *) linitial(objargs)));
 			break;
 		case OBJECT_TRIGGER:
-			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			prepare_notice_recheck_parent("trigger \"%s\" for table \"%s\" does not exist, skipping",
+								    objname,
+									    &msg, &name, &args);
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_RULE:
-			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			prepare_notice_recheck_parent("rule \"%s\" for relation \"%s\" does not exist, skipping",
+								    objname,
+									    &msg, &name, &args);
 			break;
 		case OBJECT_FDW:
 			msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 8599401..663b438 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -173,7 +173,11 @@ NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, s
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exists, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exists, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for relation "test_exists" does not exist, skip
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exists, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exists, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index 6330566..8977357 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON test_exists;
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
#61Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#57)
1 attachment(s)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

attached patch implement unified behave for DROP IF EXISTS statements as
was discussed

Regards

Pavel

2013/11/27 Dean Rasheed <dean.a.rasheed@gmail.com>

Show quoted text

On 26 November 2013 19:54, Peter Eisentraut <peter_e@gmx.net> wrote:

On 11/24/13, 2:28 PM, Pavel Stehule wrote:

Note: DROP TRIGGER ON tablename is PostgreSQL feature - no other
databases (without PostgreSQL forks) uses this syntax - so we don't need
thinking what is in (or what will be) in ANSI standard (or what other
databases does). In this moment syntax of DROP TRIGGER is non standard.
So if we can adopt design (idea) in SQL anywhere or MySQL, then DROP
TRIGGER IF EXISTS should be enough. In our implementation there are two
conditions, but we should not to check if target table exists (from
statement purpose).

Right, we might as well consider 'trigger ON tablename' to be the full
name of the trigger and just treat it like a unit.

Yeah, that's how I would view it.

But then a single IF EXISTS clause is still inconsistent with DROP TABLE
nonexistent.foo, which fails if the schema does not exist. In other
words, the IF EXISTS clause only applies to the end of an name chain.

Actually the IF EXISTS in DROP TABLE now applies to the schema as
well. Unfortunately there is currently no consistency across the
various DROP commands --- some tolerate a non-existent schema, while
others error out. Also amongst those that tolerate a non-existent
schema, the resulting notices are not consistent --- some report the
schema-qualified object name, while others just report the local
object name.

Here is the current state of HEAD:

DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
ERROR: schema "no_such_schema" does not exist

DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
ERROR: schema "no_such_schema" does not exist

DROP COLLATION IF EXISTS no_such_schema.foo;
NOTICE: collation "no_such_schema.foo" does not exist, skipping
DROP COLLATION

DROP CONVERSION IF EXISTS no_such_schema.foo;
NOTICE: conversion "no_such_schema.foo" does not exist, skipping
DROP CONVERSION

DROP DOMAIN IF EXISTS no_such_schema.foo;
ERROR: schema "no_such_schema" does not exist

DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
NOTICE: foreign table "foo" does not exist, skipping
DROP FOREIGN TABLE

DROP FUNCTION IF EXISTS no_such_schema.foo();
ERROR: schema "no_such_schema" does not exist

DROP INDEX IF EXISTS no_such_schema.foo;
NOTICE: index "foo" does not exist, skipping
DROP INDEX

DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
NOTICE: materialized view "foo" does not exist, skipping
DROP MATERIALIZED VIEW

DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
ERROR: schema "no_such_schema" does not exist

DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
ERROR: schema "no_such_schema" does not exist

DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
ERROR: schema "no_such_schema" does not exist

DROP RULE IF EXISTS foo ON no_such_schema.bar;
ERROR: schema "no_such_schema" does not exist

DROP SEQUENCE IF EXISTS no_such_schema.foo;
NOTICE: sequence "foo" does not exist, skipping
DROP SEQUENCE

DROP TABLE IF EXISTS no_such_schema.foo;
NOTICE: table "foo" does not exist, skipping
DROP TABLE

DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
NOTICE: text search configuration "no_such_schema.foo" does not exist,
skipping
DROP TEXT SEARCH CONFIGURATION

DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
NOTICE: text search dictionary "no_such_schema.foo" does not exist,
skipping
DROP TEXT SEARCH DICTIONARY

DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
NOTICE: text search parser "no_such_schema.foo" does not exist, skipping
DROP TEXT SEARCH PARSER

DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
NOTICE: text search template "no_such_schema.foo" does not exist, skipping
DROP TEXT SEARCH TEMPLATE

DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
ERROR: schema "no_such_schema" does not exist

DROP TYPE IF EXISTS no_such_schema.foo;
ERROR: schema "no_such_schema" does not exist

DROP VIEW IF EXISTS no_such_schema.foo;
NOTICE: view "foo" does not exist, skipping
DROP VIEW

That's a lot of inconsistency --- 10 errors vs 12 notices (6 with
schema-qualified names and 6 with only local names).

Regards,
Dean

Attachments:

drop-if-exists.patchtext/x-patch; charset=US-ASCII; name=drop-if-exists.patchDownload
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 4434dd6..945f757 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -909,7 +909,7 @@ TypeIsVisible(Oid typid)
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-					  bool expand_variadic, bool expand_defaults)
+					  bool expand_variadic, bool expand_defaults, bool noError)
 {
 	FuncCandidateList resultList = NULL;
 	bool		any_special = false;
@@ -928,7 +928,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 	if (schemaname)
 	{
 		/* use exact schema given */
-		namespaceId = LookupExplicitNamespace(schemaname, false);
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (!OidIsValid(namespaceId))
+			return NULL;
 	}
 	else
 	{
@@ -1414,7 +1416,7 @@ FunctionIsVisible(Oid funcid)
 		visible = false;
 
 		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-									  nargs, NIL, false, false);
+									  nargs, NIL, false, false, false);
 
 		for (; clist; clist = clist->next)
 		{
@@ -1446,7 +1448,7 @@ FunctionIsVisible(Oid funcid)
  * namespace search path.
  */
 Oid
-OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError)
 {
 	char	   *schemaname;
 	char	   *opername;
@@ -1462,18 +1464,21 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
 		Oid			namespaceId;
 		HeapTuple	opertup;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		opertup = SearchSysCache4(OPERNAMENSP,
-								  CStringGetDatum(opername),
-								  ObjectIdGetDatum(oprleft),
-								  ObjectIdGetDatum(oprright),
-								  ObjectIdGetDatum(namespaceId));
-		if (HeapTupleIsValid(opertup))
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (OidIsValid(namespaceId))
 		{
-			Oid			result = HeapTupleGetOid(opertup);
+			opertup = SearchSysCache4(OPERNAMENSP,
+									  CStringGetDatum(opername),
+									  ObjectIdGetDatum(oprleft),
+									  ObjectIdGetDatum(oprright),
+									  ObjectIdGetDatum(namespaceId));
+			if (HeapTupleIsValid(opertup))
+			{
+				Oid			result = HeapTupleGetOid(opertup);
 
-			ReleaseSysCache(opertup);
-			return result;
+				ReleaseSysCache(opertup);
+				return result;
+			}
 		}
 		return InvalidOid;
 	}
@@ -1734,7 +1739,8 @@ OperatorIsVisible(Oid oprid)
 		char	   *oprname = NameStr(oprform->oprname);
 
 		visible = (OpernameGetOprid(list_make1(makeString(oprname)),
-									oprform->oprleft, oprform->oprright)
+									oprform->oprleft, oprform->oprright,
+											    false)
 				   == oprid);
 	}
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 9011190..6a851fa 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -580,8 +580,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				{
 					TypeName   *sourcetype = (TypeName *) linitial(objname);
 					TypeName   *targettype = (TypeName *) linitial(objargs);
-					Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
-					Oid			targettypeid = typenameTypeId(NULL, targettype);
+					Oid	 sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+					Oid	 targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
 
 					address.classId = CastRelationId;
 					address.objectId =
@@ -942,26 +942,30 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_ok);
+
+		reloid = (relation != NULL) ? RelationGetRelid(relation) : InvalidOid;
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			default:
@@ -975,7 +979,9 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 		/* Avoid relcache leak when object not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			heap_close(relation, AccessShareLock);
+			if (relation != NULL)
+				heap_close(relation, AccessShareLock);
+
 			relation = NULL;	/* department of accident prevention */
 			return address;
 		}
@@ -1052,7 +1058,7 @@ get_object_address_type(ObjectType objtype,
 	address.objectId = InvalidOid;
 	address.objectSubId = 0;
 
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, missing_ok);
 	if (!HeapTupleIsValid(tup))
 	{
 		if (!missing_ok)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..c0e1e25 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -23,6 +23,7 @@
 #include "catalog/pg_class.h"
 #include "catalog/pg_proc.h"
 #include "commands/defrem.h"
+#include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "parser/parse_type.h"
@@ -32,6 +33,15 @@
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
 
+static void parent_not_exist_skipping(const char *message,
+						List *objname,
+								const char **msg,
+								char **name,
+								char **args);
+static bool schema_not_exist_skipping(List *objname,
+						const char **msg, char **name);
+
+
 /*
  * Drop one or more objects.
  *
@@ -125,6 +135,73 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * Prepare text of "does not exist, skipping" message for triggers and rules,
+ * where we check schema name first, then table name, and as last we raise
+ * message about missing object.
+ */
+static void
+parent_not_exist_skipping(const char *message, List *objname,
+							const char **msg,
+							char **name,
+							char **args)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(list_truncate(list_copy(objname),
+							list_length(objname) - 1));
+
+	if (rel->schemaname != NULL && !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exists, skipping");
+		*name = rel->schemaname;
+		*args = NULL;
+	}
+	else if (!OidIsValid(RangeVarGetRelid(rel, NoLock, true)))
+	{
+		*msg = gettext_noop("relation \"%s\" does not exists, skipping");
+		*name = rel->relname;
+		*args = NULL;
+	}
+	else
+	{
+		StringInfoData string;
+
+		*msg = message;
+		*name = strVal(llast(objname));
+
+		initStringInfo(&string);
+		if (rel->schemaname != NULL)
+		{
+			appendStringInfoString(&string, rel->schemaname);
+			appendStringInfoChar(&string, '.');
+		}
+		appendStringInfoString(&string, rel->relname);
+
+		*args = string.data;
+	}
+}
+
+static bool
+schema_not_exist_skipping(List *objname,
+					const char **msg,
+					char **name)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(objname);
+
+	if (rel->schemaname != NULL && !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exists, skipping");
+		*name = rel->schemaname;
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
  * get_object_address() will throw an ERROR.
@@ -140,99 +217,146 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			msg = gettext_noop("type \"%s\" does not exist, skipping");
-			name = TypeNameToString(makeTypeNameFromNameList(objname));
-			break;
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("type \"%s\" does not exist, skipping");
+				name = TypeNameToString(makeTypeNameFromNameList(objname));
+			}
+				break;
 		case OBJECT_COLLATION:
-			msg = gettext_noop("collation \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("collation \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_CONVERSION:
-			msg = gettext_noop("conversion \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_SCHEMA:
 			msg = gettext_noop("schema \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_TSPARSER:
-			msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSDICTIONARY:
-			msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSTEMPLATE:
-			msg = gettext_noop("text search template \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSCONFIGURATION:
-			msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_EXTENSION:
-			msg = gettext_noop("extension \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("extension \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_FUNCTION:
-			msg = gettext_noop("function %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("function %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_AGGREGATE:
-			msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_OPERATOR:
-			msg = gettext_noop("operator %s does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator %s does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_LANGUAGE:
 			msg = gettext_noop("language \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_CAST:
-			msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
-			name = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objname)));
-			args = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objargs)));
+			{
+				TypeName *tobjname = (TypeName *) linitial(objname);
+				TypeName *targname = (TypeName *) linitial(objargs);
+
+				if (!schema_not_exist_skipping(tobjname->names, &msg, &name)
+						 && !schema_not_exist_skipping(targname->names, &msg, &name))
+				{
+					msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+					name = format_type_be(typenameTypeId(NULL, tobjname));
+					args = format_type_be(typenameTypeId(NULL, targname));
+				}
+			}
 			break;
 		case OBJECT_TRIGGER:
-			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			parent_not_exist_skipping("trigger \"%s\" for table \"%s\" does not exist, skipping",
+								    objname,
+									    &msg, &name, &args);
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_RULE:
-			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			parent_not_exist_skipping("rule \"%s\" for relation \"%s\" does not exist, skipping",
+								    objname,
+									    &msg, &name, &args);
 			break;
 		case OBJECT_FDW:
-			msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			msg = gettext_noop("server \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_OPCLASS:
-			msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		case OBJECT_OPFAMILY:
-			msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		default:
 			elog(ERROR, "unexpected object type (%d)", (int) objtype);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ca754b4..348b901 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -86,7 +86,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
 	Type		typtup;
 	AclResult	aclresult;
 
-	typtup = LookupTypeName(NULL, returnType, NULL);
+	typtup = LookupTypeName(NULL, returnType, NULL, false);
 
 	if (typtup)
 	{
@@ -220,7 +220,7 @@ interpret_function_parameter_list(List *parameters,
 		Type		typtup;
 		AclResult	aclresult;
 
-		typtup = LookupTypeName(NULL, t, NULL);
+		typtup = LookupTypeName(NULL, t, NULL, false);
 		if (typtup)
 		{
 			if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 3140b37..3f2329b 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -179,11 +179,14 @@ OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(CLAAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opcname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(CLAAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opcname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3483107..3fc37fe 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -690,10 +690,20 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  * non-existent relation
  */
 static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(const char *relname, const char *schemaname, char rightkind, bool missing_ok)
 {
 	const struct dropmsgstrings *rentry;
 
+	/* schema should be wrong */
+	if (missing_ok && schemaname != NULL &&
+				!OidIsValid(LookupNamespaceNoError(schemaname)))
+	{
+		ereport(NOTICE,
+			       (errmsg(gettext_noop("schema \"%s\" does not exists, skipping"),
+							schemaname)));
+		return;
+	}
+
 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
 	{
 		if (rentry->kind == rightkind)
@@ -845,7 +855,8 @@ RemoveRelations(DropStmt *drop)
 		/* Not there? */
 		if (!OidIsValid(relOid))
 		{
-			DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+			DropErrorMsgNonExistent(rel->relname, rel->schemaname,
+									    relkind, drop->missing_ok);
 			continue;
 		}
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..4805f2b 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3245,7 +3245,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 	typename = makeTypeNameFromNameList(names);
 
 	/* Use LookupTypeName here so that shell types can be processed */
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index ede36d1..1e57ccb 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1062,7 +1062,8 @@ func_get_detail(List *funcname,
 
 	/* Get list of possible candidates from namespace search */
 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
-										   expand_variadic, expand_defaults);
+										   expand_variadic, expand_defaults, 
+													    false);
 
 	/*
 	 * Quickly check if there is an exact match to the input datatypes (there
@@ -1422,7 +1423,7 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
 	if (typtup == NULL)
 		return InvalidOid;
 
@@ -1581,7 +1582,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 {
 	FuncCandidateList clist;
 
-	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
 
 	while (clist)
 	{
@@ -1601,27 +1602,6 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 }
 
 /*
- * LookupTypeNameOid
- *		Convenience routine to look up a type, silently accepting shell types
- */
-static Oid
-LookupTypeNameOid(const TypeName *typename)
-{
-	Oid			result;
-	Type		typtup;
-
-	typtup = LookupTypeName(NULL, typename, NULL);
-	if (typtup == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename))));
-	result = typeTypeId(typtup);
-	ReleaseSysCache(typtup);
-	return result;
-}
-
-/*
  * LookupFuncNameTypeNames
  *		Like LookupFuncName, but the argument types are specified by a
  *		list of TypeName nodes.
@@ -1648,7 +1628,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
 	{
 		TypeName   *t = (TypeName *) lfirst(args_item);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		args_item = lnext(args_item);
 	}
 
@@ -1688,7 +1668,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
 	{
 		TypeName   *t = (TypeName *) lfirst(lc);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		i++;
 	}
 
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index dd80fa9..9595f10 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -103,7 +103,7 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 {
 	Oid			result;
 
-	result = OpernameGetOprid(opername, oprleft, oprright);
+	result = OpernameGetOprid(opername, oprleft, oprright, noError);
 	if (OidIsValid(result))
 		return result;
 
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername,
 	if (oprleft == NULL)
 		leftoid = InvalidOid;
 	else
-		leftoid = typenameTypeId(pstate, oprleft);
+		leftoid = LookupTypeNameOid(pstate, oprleft, noError);
 
 	if (oprright == NULL)
 		rightoid = InvalidOid;
 	else
-		rightoid = typenameTypeId(pstate, oprright);
+		rightoid = LookupTypeNameOid(pstate, oprright, noError);
 
 	return LookupOperName(pstate, opername, leftoid, rightoid,
 						  noError, location);
@@ -280,7 +280,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 		was_unknown = true;
 	}
 
-	result = OpernameGetOprid(opname, arg1, arg2);
+	result = OpernameGetOprid(opname, arg1, arg2, false);
 	if (OidIsValid(result))
 		return result;
 
@@ -291,7 +291,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 
 		if (basetype != arg1)
 		{
-			result = OpernameGetOprid(opname, basetype, basetype);
+			result = OpernameGetOprid(opname, basetype, basetype, false);
 			if (OidIsValid(result))
 				return result;
 		}
@@ -544,7 +544,7 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
+	operOid = OpernameGetOprid(op, arg, InvalidOid, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
@@ -622,7 +622,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, InvalidOid, arg);
+	operOid = OpernameGetOprid(op, InvalidOid, arg, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ee6802a..c2ce134 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -56,7 +56,8 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p)
+			   int32 *typmod_p,
+					     bool missing_ok)
 {
 	Oid			typoid;
 	HeapTuple	tup;
@@ -116,15 +117,21 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 		 * concurrent DDL.	But taking a lock would carry a performance
 		 * penalty and would also require a permissions check.
 		 */
-		relid = RangeVarGetRelid(rel, NoLock, false);
-		attnum = get_attnum(relid, field);
-		if (attnum == InvalidAttrNumber)
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_COLUMN),
-					 errmsg("column \"%s\" of relation \"%s\" does not exist",
-							field, rel->relname),
-					 parser_errposition(pstate, typeName->location)));
-		typoid = get_atttype(relid, attnum);
+		typoid = InvalidOid;
+		relid = RangeVarGetRelid(rel, NoLock, missing_ok);
+
+		if (OidIsValid(relid))
+		{
+			attnum = get_attnum(relid, field);
+			if (attnum != InvalidAttrNumber)
+				typoid = get_atttype(relid, attnum);
+			else if (!missing_ok)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_COLUMN),
+						 errmsg("column \"%s\" of relation \"%s\" does not exist",
+								field, rel->relname),
+						 parser_errposition(pstate, typeName->location)));
+		}
 
 		/* this construct should never have an array indicator */
 		Assert(typeName->arrayBounds == NIL);
@@ -149,10 +156,13 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			/* Look in specific schema only */
 			Oid			namespaceId;
 
-			namespaceId = LookupExplicitNamespace(schemaname, false);
-			typoid = GetSysCacheOid2(TYPENAMENSP,
+			namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+			if (OidIsValid(namespaceId))
+				typoid = GetSysCacheOid2(TYPENAMENSP,
 									 PointerGetDatum(typname),
 									 ObjectIdGetDatum(namespaceId));
+			else
+				typoid = InvalidOid;
 		}
 		else
 		{
@@ -196,7 +206,7 @@ typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typeName, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -232,6 +242,35 @@ typenameTypeId(ParseState *pstate, const TypeName *typeName)
 }
 
 /*
+ * returns oid of type
+ *		Convenience routine to look up a type, silently accepting shell types
+ */
+Oid
+LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
+{
+	Oid			typoid;
+	Type		tup;
+
+	tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
+	if (tup == NULL)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typeName)),
+					 parser_errposition(pstate, typeName->location)));
+
+		return InvalidOid;
+	}
+
+	typoid = HeapTupleGetOid(tup);
+	ReleaseSysCache(tup);
+
+	return typoid;
+}
+
+/*
  * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
  *
  * This is equivalent to typenameType, but we only hand back the type OID
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index c24a2c1..28c1e7f 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -135,7 +135,7 @@ regprocin(PG_FUNCTION_ARGS)
 	 * pg_proc entries in the current search path.
 	 */
 	names = stringToQualifiedNameList(pro_name_or_oid);
-	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
+	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
 
 	if (clist == NULL)
 		ereport(ERROR,
@@ -192,7 +192,7 @@ regprocout(PG_FUNCTION_ARGS)
 			 * qualify it.
 			 */
 			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-										  -1, NIL, false, false);
+										  -1, NIL, false, false, false);
 			if (clist != NULL && clist->next == NULL &&
 				clist->oid == proid)
 				nspname = NULL;
@@ -279,7 +279,7 @@ regprocedurein(PG_FUNCTION_ARGS)
 	 */
 	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
 
-	clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
 
 	for (; clist; clist = clist->next)
 	{
@@ -661,7 +661,7 @@ regoperatorin(PG_FUNCTION_ARGS)
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
 
-	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
+	result = OpernameGetOprid(names, argtypes[0], argtypes[1], false);
 
 	if (!OidIsValid(result))
 		ereport(ERROR,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 4fadc74..05c035b 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -71,10 +71,11 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names,
 					  int nargs, List *argnames,
 					  bool expand_variadic,
-					  bool expand_defaults);
+					  bool expand_defaults,
+					  bool noError);
 extern bool FunctionIsVisible(Oid funcid);
 
-extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
+extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 340121a..72505fb 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,7 +20,9 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p);
+			   int32 *typmod_p, bool missing_ok);
+Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
+			    bool missing_ok);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
 extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 426aeb5..692bba4 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1665,7 +1665,7 @@ plpgsql_parse_wordtype(char *ident)
 	 * Word wasn't found in the namespace stack. Try to find a data type with
 	 * that name, but ignore shell types and complex types.
 	 */
-	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, false);
 	if (typeTup)
 	{
 		Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 8599401..8e37df6 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -173,7 +173,11 @@ NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, s
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exists, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exists, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for relation "test_exists" does not exist, skip
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exists, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exists, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -223,3 +231,48 @@ ERROR:  access method "no_such_am" does not exist
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
 ERROR:  table "test_exists" does not exist
+-- be toleralnt with not existing schema
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 656d47f..312d89e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -280,7 +280,7 @@ SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
 (23 rows)
 
 DROP OWNED BY regression_bob;
-NOTICE:  table "audit_tbls_schema_one_table_two" does not exist, skipping
+NOTICE:  schema "audit_tbls" does not exists, skipping
 CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index 6330566..a2f265d 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON test_exists;
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -226,3 +232,28 @@ DROP OPERATOR FAMILY IF EXISTS test_operator_family USING no_such_am;
 DROP TABLE IF EXISTS test_exists;
 
 DROP TABLE test_exists;
+
+-- be toleralnt with not existing schema
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+DROP COLLATION IF EXISTS no_such_schema.foo;
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+DROP INDEX IF EXISTS no_such_schema.foo;
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+DROP TABLE IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+DROP TYPE IF EXISTS no_such_schema.foo;
+DROP VIEW IF EXISTS no_such_schema.foo;
#62Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#61)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On Fri, 2013-11-29 at 09:06 +0100, Pavel Stehule wrote:

attached patch implement unified behave for DROP IF EXISTS statements
as was discussed

src/backend/catalog/namespace.c:1743: indent with spaces.
src/backend/commands/dropcmds.c:322: indent with spaces.
src/backend/commands/dropcmds.c:323: indent with spaces.
src/backend/commands/dropcmds.c:331: indent with spaces.
src/backend/commands/dropcmds.c:332: indent with spaces.
src/backend/commands/tablecmds.c:702: indent with spaces.
src/backend/commands/tablecmds.c:859: indent with spaces.
src/backend/parser/parse_func.c:1065: trailing whitespace.
src/backend/parser/parse_func.c:1066: indent with spaces.
src/backend/parser/parse_type.c:60: indent with spaces.
src/include/parser/parse_type.h:25: indent with spaces.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#63Pavel Stehule
pavel.stehule@gmail.com
In reply to: Andres Freund (#28)
1 attachment(s)
Fwd: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/11/30 Peter Eisentraut <peter_e@gmx.net>

trailing whitespace

fixed,

Peter, what application do you use for this check?

Regards

Pavel

Attachments:

drop-if-exists-consistency.patchtext/x-patch; charset=US-ASCII; name=drop-if-exists-consistency.patchDownload
commit 88e0a6b97968f88aaa1e3cef17fc2e6e2ca9f25d
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Fri Nov 29 11:10:07 2013 +0100

    initial

diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 4434dd6..b32f2e4 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -909,7 +909,7 @@ TypeIsVisible(Oid typid)
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-					  bool expand_variadic, bool expand_defaults)
+					  bool expand_variadic, bool expand_defaults, bool noError)
 {
 	FuncCandidateList resultList = NULL;
 	bool		any_special = false;
@@ -928,7 +928,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 	if (schemaname)
 	{
 		/* use exact schema given */
-		namespaceId = LookupExplicitNamespace(schemaname, false);
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (!OidIsValid(namespaceId))
+			return NULL;
 	}
 	else
 	{
@@ -1414,7 +1416,7 @@ FunctionIsVisible(Oid funcid)
 		visible = false;
 
 		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-									  nargs, NIL, false, false);
+									  nargs, NIL, false, false, false);
 
 		for (; clist; clist = clist->next)
 		{
@@ -1446,7 +1448,7 @@ FunctionIsVisible(Oid funcid)
  * namespace search path.
  */
 Oid
-OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError)
 {
 	char	   *schemaname;
 	char	   *opername;
@@ -1462,18 +1464,21 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
 		Oid			namespaceId;
 		HeapTuple	opertup;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		opertup = SearchSysCache4(OPERNAMENSP,
-								  CStringGetDatum(opername),
-								  ObjectIdGetDatum(oprleft),
-								  ObjectIdGetDatum(oprright),
-								  ObjectIdGetDatum(namespaceId));
-		if (HeapTupleIsValid(opertup))
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (OidIsValid(namespaceId))
 		{
-			Oid			result = HeapTupleGetOid(opertup);
+			opertup = SearchSysCache4(OPERNAMENSP,
+									  CStringGetDatum(opername),
+									  ObjectIdGetDatum(oprleft),
+									  ObjectIdGetDatum(oprright),
+									  ObjectIdGetDatum(namespaceId));
+			if (HeapTupleIsValid(opertup))
+			{
+				Oid			result = HeapTupleGetOid(opertup);
 
-			ReleaseSysCache(opertup);
-			return result;
+				ReleaseSysCache(opertup);
+				return result;
+			}
 		}
 		return InvalidOid;
 	}
@@ -1734,7 +1739,8 @@ OperatorIsVisible(Oid oprid)
 		char	   *oprname = NameStr(oprform->oprname);
 
 		visible = (OpernameGetOprid(list_make1(makeString(oprname)),
-									oprform->oprleft, oprform->oprright)
+									oprform->oprleft, oprform->oprright,
+											   false)
 				   == oprid);
 	}
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 9011190..6a851fa 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -580,8 +580,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				{
 					TypeName   *sourcetype = (TypeName *) linitial(objname);
 					TypeName   *targettype = (TypeName *) linitial(objargs);
-					Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
-					Oid			targettypeid = typenameTypeId(NULL, targettype);
+					Oid	 sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+					Oid	 targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
 
 					address.classId = CastRelationId;
 					address.objectId =
@@ -942,26 +942,30 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_ok);
+
+		reloid = (relation != NULL) ? RelationGetRelid(relation) : InvalidOid;
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			default:
@@ -975,7 +979,9 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 		/* Avoid relcache leak when object not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			heap_close(relation, AccessShareLock);
+			if (relation != NULL)
+				heap_close(relation, AccessShareLock);
+
 			relation = NULL;	/* department of accident prevention */
 			return address;
 		}
@@ -1052,7 +1058,7 @@ get_object_address_type(ObjectType objtype,
 	address.objectId = InvalidOid;
 	address.objectSubId = 0;
 
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, missing_ok);
 	if (!HeapTupleIsValid(tup))
 	{
 		if (!missing_ok)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..9b29f5d 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -23,6 +23,7 @@
 #include "catalog/pg_class.h"
 #include "catalog/pg_proc.h"
 #include "commands/defrem.h"
+#include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "parser/parse_type.h"
@@ -32,6 +33,15 @@
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
 
+static void parent_not_exist_skipping(const char *message,
+						List *objname,
+								const char **msg,
+								char **name,
+								char **args);
+static bool schema_not_exist_skipping(List *objname,
+						const char **msg, char **name);
+
+
 /*
  * Drop one or more objects.
  *
@@ -125,6 +135,73 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * Prepare text of "does not exist, skipping" message for triggers and rules,
+ * where we check schema name first, then table name, and as last we raise
+ * message about missing object.
+ */
+static void
+parent_not_exist_skipping(const char *message, List *objname,
+							const char **msg,
+							char **name,
+							char **args)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(list_truncate(list_copy(objname),
+							list_length(objname) - 1));
+
+	if (rel->schemaname != NULL && !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exists, skipping");
+		*name = rel->schemaname;
+		*args = NULL;
+	}
+	else if (!OidIsValid(RangeVarGetRelid(rel, NoLock, true)))
+	{
+		*msg = gettext_noop("relation \"%s\" does not exists, skipping");
+		*name = rel->relname;
+		*args = NULL;
+	}
+	else
+	{
+		StringInfoData string;
+
+		*msg = message;
+		*name = strVal(llast(objname));
+
+		initStringInfo(&string);
+		if (rel->schemaname != NULL)
+		{
+			appendStringInfoString(&string, rel->schemaname);
+			appendStringInfoChar(&string, '.');
+		}
+		appendStringInfoString(&string, rel->relname);
+
+		*args = string.data;
+	}
+}
+
+static bool
+schema_not_exist_skipping(List *objname,
+					const char **msg,
+					char **name)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(objname);
+
+	if (rel->schemaname != NULL && !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exists, skipping");
+		*name = rel->schemaname;
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
  * get_object_address() will throw an ERROR.
@@ -140,99 +217,146 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			msg = gettext_noop("type \"%s\" does not exist, skipping");
-			name = TypeNameToString(makeTypeNameFromNameList(objname));
-			break;
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("type \"%s\" does not exist, skipping");
+				name = TypeNameToString(makeTypeNameFromNameList(objname));
+			}
+				break;
 		case OBJECT_COLLATION:
-			msg = gettext_noop("collation \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("collation \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_CONVERSION:
-			msg = gettext_noop("conversion \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_SCHEMA:
 			msg = gettext_noop("schema \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_TSPARSER:
-			msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSDICTIONARY:
-			msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSTEMPLATE:
-			msg = gettext_noop("text search template \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSCONFIGURATION:
-			msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_EXTENSION:
-			msg = gettext_noop("extension \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("extension \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_FUNCTION:
-			msg = gettext_noop("function %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("function %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_AGGREGATE:
-			msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_OPERATOR:
-			msg = gettext_noop("operator %s does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator %s does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_LANGUAGE:
 			msg = gettext_noop("language \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_CAST:
-			msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
-			name = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objname)));
-			args = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objargs)));
+			{
+				TypeName *tobjname = (TypeName *) linitial(objname);
+				TypeName *targname = (TypeName *) linitial(objargs);
+
+				if (!schema_not_exist_skipping(tobjname->names, &msg, &name)
+						 && !schema_not_exist_skipping(targname->names, &msg, &name))
+				{
+					msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+					name = format_type_be(typenameTypeId(NULL, tobjname));
+					args = format_type_be(typenameTypeId(NULL, targname));
+				}
+			}
 			break;
 		case OBJECT_TRIGGER:
-			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			parent_not_exist_skipping("trigger \"%s\" for table \"%s\" does not exist, skipping",
+								   objname,
+									   &msg, &name, &args);
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_RULE:
-			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			parent_not_exist_skipping("rule \"%s\" for relation \"%s\" does not exist, skipping",
+								   objname,
+									   &msg, &name, &args);
 			break;
 		case OBJECT_FDW:
-			msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			msg = gettext_noop("server \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_OPCLASS:
-			msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		case OBJECT_OPFAMILY:
-			msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		default:
 			elog(ERROR, "unexpected object type (%d)", (int) objtype);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ca754b4..348b901 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -86,7 +86,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
 	Type		typtup;
 	AclResult	aclresult;
 
-	typtup = LookupTypeName(NULL, returnType, NULL);
+	typtup = LookupTypeName(NULL, returnType, NULL, false);
 
 	if (typtup)
 	{
@@ -220,7 +220,7 @@ interpret_function_parameter_list(List *parameters,
 		Type		typtup;
 		AclResult	aclresult;
 
-		typtup = LookupTypeName(NULL, t, NULL);
+		typtup = LookupTypeName(NULL, t, NULL, false);
 		if (typtup)
 		{
 			if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 3140b37..3f2329b 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -179,11 +179,14 @@ OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(CLAAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opcname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(CLAAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opcname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3483107..8de4ce5 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -690,10 +690,20 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  * non-existent relation
  */
 static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(const char *relname, const char *schemaname, char rightkind, bool missing_ok)
 {
 	const struct dropmsgstrings *rentry;
 
+	/* schema should be wrong */
+	if (missing_ok && schemaname != NULL &&
+				!OidIsValid(LookupNamespaceNoError(schemaname)))
+	{
+		ereport(NOTICE,
+				 (errmsg(gettext_noop("schema \"%s\" does not exists, skipping"),
+							schemaname)));
+		return;
+	}
+
 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
 	{
 		if (rentry->kind == rightkind)
@@ -845,7 +855,8 @@ RemoveRelations(DropStmt *drop)
 		/* Not there? */
 		if (!OidIsValid(relOid))
 		{
-			DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+			DropErrorMsgNonExistent(rel->relname, rel->schemaname,
+										 relkind, drop->missing_ok);
 			continue;
 		}
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..4805f2b 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3245,7 +3245,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 	typename = makeTypeNameFromNameList(names);
 
 	/* Use LookupTypeName here so that shell types can be processed */
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index ede36d1..f560b48 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1062,7 +1062,8 @@ func_get_detail(List *funcname,
 
 	/* Get list of possible candidates from namespace search */
 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
-										   expand_variadic, expand_defaults);
+										   expand_variadic, expand_defaults,
+													   false);
 
 	/*
 	 * Quickly check if there is an exact match to the input datatypes (there
@@ -1422,7 +1423,7 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
 	if (typtup == NULL)
 		return InvalidOid;
 
@@ -1581,7 +1582,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 {
 	FuncCandidateList clist;
 
-	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
 
 	while (clist)
 	{
@@ -1601,27 +1602,6 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 }
 
 /*
- * LookupTypeNameOid
- *		Convenience routine to look up a type, silently accepting shell types
- */
-static Oid
-LookupTypeNameOid(const TypeName *typename)
-{
-	Oid			result;
-	Type		typtup;
-
-	typtup = LookupTypeName(NULL, typename, NULL);
-	if (typtup == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename))));
-	result = typeTypeId(typtup);
-	ReleaseSysCache(typtup);
-	return result;
-}
-
-/*
  * LookupFuncNameTypeNames
  *		Like LookupFuncName, but the argument types are specified by a
  *		list of TypeName nodes.
@@ -1648,7 +1628,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
 	{
 		TypeName   *t = (TypeName *) lfirst(args_item);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		args_item = lnext(args_item);
 	}
 
@@ -1688,7 +1668,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
 	{
 		TypeName   *t = (TypeName *) lfirst(lc);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		i++;
 	}
 
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index dd80fa9..9595f10 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -103,7 +103,7 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 {
 	Oid			result;
 
-	result = OpernameGetOprid(opername, oprleft, oprright);
+	result = OpernameGetOprid(opername, oprleft, oprright, noError);
 	if (OidIsValid(result))
 		return result;
 
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername,
 	if (oprleft == NULL)
 		leftoid = InvalidOid;
 	else
-		leftoid = typenameTypeId(pstate, oprleft);
+		leftoid = LookupTypeNameOid(pstate, oprleft, noError);
 
 	if (oprright == NULL)
 		rightoid = InvalidOid;
 	else
-		rightoid = typenameTypeId(pstate, oprright);
+		rightoid = LookupTypeNameOid(pstate, oprright, noError);
 
 	return LookupOperName(pstate, opername, leftoid, rightoid,
 						  noError, location);
@@ -280,7 +280,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 		was_unknown = true;
 	}
 
-	result = OpernameGetOprid(opname, arg1, arg2);
+	result = OpernameGetOprid(opname, arg1, arg2, false);
 	if (OidIsValid(result))
 		return result;
 
@@ -291,7 +291,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 
 		if (basetype != arg1)
 		{
-			result = OpernameGetOprid(opname, basetype, basetype);
+			result = OpernameGetOprid(opname, basetype, basetype, false);
 			if (OidIsValid(result))
 				return result;
 		}
@@ -544,7 +544,7 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
+	operOid = OpernameGetOprid(op, arg, InvalidOid, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
@@ -622,7 +622,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, InvalidOid, arg);
+	operOid = OpernameGetOprid(op, InvalidOid, arg, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ee6802a..c72fc8d 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -56,7 +56,8 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p)
+			   int32 *typmod_p,
+					bool missing_ok)
 {
 	Oid			typoid;
 	HeapTuple	tup;
@@ -116,15 +117,21 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 		 * concurrent DDL.	But taking a lock would carry a performance
 		 * penalty and would also require a permissions check.
 		 */
-		relid = RangeVarGetRelid(rel, NoLock, false);
-		attnum = get_attnum(relid, field);
-		if (attnum == InvalidAttrNumber)
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_COLUMN),
-					 errmsg("column \"%s\" of relation \"%s\" does not exist",
-							field, rel->relname),
-					 parser_errposition(pstate, typeName->location)));
-		typoid = get_atttype(relid, attnum);
+		typoid = InvalidOid;
+		relid = RangeVarGetRelid(rel, NoLock, missing_ok);
+
+		if (OidIsValid(relid))
+		{
+			attnum = get_attnum(relid, field);
+			if (attnum != InvalidAttrNumber)
+				typoid = get_atttype(relid, attnum);
+			else if (!missing_ok)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_COLUMN),
+						 errmsg("column \"%s\" of relation \"%s\" does not exist",
+								field, rel->relname),
+						 parser_errposition(pstate, typeName->location)));
+		}
 
 		/* this construct should never have an array indicator */
 		Assert(typeName->arrayBounds == NIL);
@@ -149,10 +156,13 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			/* Look in specific schema only */
 			Oid			namespaceId;
 
-			namespaceId = LookupExplicitNamespace(schemaname, false);
-			typoid = GetSysCacheOid2(TYPENAMENSP,
+			namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+			if (OidIsValid(namespaceId))
+				typoid = GetSysCacheOid2(TYPENAMENSP,
 									 PointerGetDatum(typname),
 									 ObjectIdGetDatum(namespaceId));
+			else
+				typoid = InvalidOid;
 		}
 		else
 		{
@@ -196,7 +206,7 @@ typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typeName, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -232,6 +242,35 @@ typenameTypeId(ParseState *pstate, const TypeName *typeName)
 }
 
 /*
+ * returns oid of type
+ *		Convenience routine to look up a type, silently accepting shell types
+ */
+Oid
+LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
+{
+	Oid			typoid;
+	Type		tup;
+
+	tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
+	if (tup == NULL)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typeName)),
+					 parser_errposition(pstate, typeName->location)));
+
+		return InvalidOid;
+	}
+
+	typoid = HeapTupleGetOid(tup);
+	ReleaseSysCache(tup);
+
+	return typoid;
+}
+
+/*
  * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
  *
  * This is equivalent to typenameType, but we only hand back the type OID
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index c24a2c1..28c1e7f 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -135,7 +135,7 @@ regprocin(PG_FUNCTION_ARGS)
 	 * pg_proc entries in the current search path.
 	 */
 	names = stringToQualifiedNameList(pro_name_or_oid);
-	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
+	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
 
 	if (clist == NULL)
 		ereport(ERROR,
@@ -192,7 +192,7 @@ regprocout(PG_FUNCTION_ARGS)
 			 * qualify it.
 			 */
 			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-										  -1, NIL, false, false);
+										  -1, NIL, false, false, false);
 			if (clist != NULL && clist->next == NULL &&
 				clist->oid == proid)
 				nspname = NULL;
@@ -279,7 +279,7 @@ regprocedurein(PG_FUNCTION_ARGS)
 	 */
 	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
 
-	clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
 
 	for (; clist; clist = clist->next)
 	{
@@ -661,7 +661,7 @@ regoperatorin(PG_FUNCTION_ARGS)
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
 
-	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
+	result = OpernameGetOprid(names, argtypes[0], argtypes[1], false);
 
 	if (!OidIsValid(result))
 		ereport(ERROR,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 4fadc74..05c035b 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -71,10 +71,11 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names,
 					  int nargs, List *argnames,
 					  bool expand_variadic,
-					  bool expand_defaults);
+					  bool expand_defaults,
+					  bool noError);
 extern bool FunctionIsVisible(Oid funcid);
 
-extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
+extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 340121a..51da025 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,7 +20,9 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p);
+			   int32 *typmod_p, bool missing_ok);
+extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
+				 bool missing_ok);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
 extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 426aeb5..692bba4 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1665,7 +1665,7 @@ plpgsql_parse_wordtype(char *ident)
 	 * Word wasn't found in the namespace stack. Try to find a data type with
 	 * that name, but ignore shell types and complex types.
 	 */
-	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, false);
 	if (typeTup)
 	{
 		Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 8599401..8e37df6 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -173,7 +173,11 @@ NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, s
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exists, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exists, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for relation "test_exists" does not exist, skip
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exists, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exists, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -223,3 +231,48 @@ ERROR:  access method "no_such_am" does not exist
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
 ERROR:  table "test_exists" does not exist
+-- be toleralnt with not existing schema
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exists, skipping
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 656d47f..312d89e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -280,7 +280,7 @@ SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
 (23 rows)
 
 DROP OWNED BY regression_bob;
-NOTICE:  table "audit_tbls_schema_one_table_two" does not exist, skipping
+NOTICE:  schema "audit_tbls" does not exists, skipping
 CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index 6330566..a2f265d 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON test_exists;
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -226,3 +232,28 @@ DROP OPERATOR FAMILY IF EXISTS test_operator_family USING no_such_am;
 DROP TABLE IF EXISTS test_exists;
 
 DROP TABLE test_exists;
+
+-- be toleralnt with not existing schema
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+DROP COLLATION IF EXISTS no_such_schema.foo;
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+DROP INDEX IF EXISTS no_such_schema.foo;
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+DROP TABLE IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+DROP TYPE IF EXISTS no_such_schema.foo;
+DROP VIEW IF EXISTS no_such_schema.foo;
#64Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Pavel Stehule (#63)
1 attachment(s)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 1 December 2013 07:32, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/11/30 Peter Eisentraut <peter_e@gmx.net>

trailing whitespace

fixed,

Hi,

I've been looking at this and I think it's mostly in good shape, but I
spotted a few minor issues:

* There's a typo in the notice text in a couple of places --- "does
not exists, skipping" should be "does not exist, skipping".

* In does_not_exist_skipping(), the schema existence checks for
extensions and foreign data wrappers are not necessary, since I don't
think they can be schema-qualified.

* Also in does_not_exist_skipping(), in the block for casts, it is no
longer safe to use format_type_be() because it is now possible for the
types to not exist at this point. So I think it needs to use
TypeNameToString() there instead, otherwise it might raise a no such
type ERROR while trying to issue the NOTICE.

* In DropErrorMsgNonExistent(), I think the ERROR text should report
no such schema in the same way as the NOTICE text when the schema
doesn't exist for consistency with the other ERRORs and NOTICEs.

* Some more code is needed to make DROP OPERATOR FAMILY IF EXISTS
tolerate a non-existent schema.

Attached is an updated patch for those issues. I also tried to tidy up
the code in dropcmds.c a bit, removing some duplicated code, and
making parent_does_not_exist_skipping() have the same signature as
schema_does_not_exist_skipping(). This makes the code in
does_not_exist_skipping() a little neater, and means that
parent_does_not_exist_skipping() can just call
schema_does_not_exist_skipping() to check for the existence of the
parent relation's schema.

I hope those changes are all OK.

Regards,
Dean

Attachments:

drop-if-exists-consistency-v2.patchapplication/octet-stream; name=drop-if-exists-consistency-v2.patchDownload
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
new file mode 100644
index 4434dd6..b32f2e4
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -909,7 +909,7 @@ TypeIsVisible(Oid typid)
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-					  bool expand_variadic, bool expand_defaults)
+					  bool expand_variadic, bool expand_defaults, bool noError)
 {
 	FuncCandidateList resultList = NULL;
 	bool		any_special = false;
@@ -928,7 +928,9 @@ FuncnameGetCandidates(List *names, int n
 	if (schemaname)
 	{
 		/* use exact schema given */
-		namespaceId = LookupExplicitNamespace(schemaname, false);
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (!OidIsValid(namespaceId))
+			return NULL;
 	}
 	else
 	{
@@ -1414,7 +1416,7 @@ FunctionIsVisible(Oid funcid)
 		visible = false;
 
 		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-									  nargs, NIL, false, false);
+									  nargs, NIL, false, false, false);
 
 		for (; clist; clist = clist->next)
 		{
@@ -1446,7 +1448,7 @@ FunctionIsVisible(Oid funcid)
  * namespace search path.
  */
 Oid
-OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError)
 {
 	char	   *schemaname;
 	char	   *opername;
@@ -1462,18 +1464,21 @@ OpernameGetOprid(List *names, Oid oprlef
 		Oid			namespaceId;
 		HeapTuple	opertup;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		opertup = SearchSysCache4(OPERNAMENSP,
-								  CStringGetDatum(opername),
-								  ObjectIdGetDatum(oprleft),
-								  ObjectIdGetDatum(oprright),
-								  ObjectIdGetDatum(namespaceId));
-		if (HeapTupleIsValid(opertup))
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (OidIsValid(namespaceId))
 		{
-			Oid			result = HeapTupleGetOid(opertup);
+			opertup = SearchSysCache4(OPERNAMENSP,
+									  CStringGetDatum(opername),
+									  ObjectIdGetDatum(oprleft),
+									  ObjectIdGetDatum(oprright),
+									  ObjectIdGetDatum(namespaceId));
+			if (HeapTupleIsValid(opertup))
+			{
+				Oid			result = HeapTupleGetOid(opertup);
 
-			ReleaseSysCache(opertup);
-			return result;
+				ReleaseSysCache(opertup);
+				return result;
+			}
 		}
 		return InvalidOid;
 	}
@@ -1734,7 +1739,8 @@ OperatorIsVisible(Oid oprid)
 		char	   *oprname = NameStr(oprform->oprname);
 
 		visible = (OpernameGetOprid(list_make1(makeString(oprname)),
-									oprform->oprleft, oprform->oprright)
+									oprform->oprleft, oprform->oprright,
+											   false)
 				   == oprid);
 	}
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
new file mode 100644
index 9011190..6a851fa
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -580,8 +580,8 @@ get_object_address(ObjectType objtype, L
 				{
 					TypeName   *sourcetype = (TypeName *) linitial(objname);
 					TypeName   *targettype = (TypeName *) linitial(objargs);
-					Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
-					Oid			targettypeid = typenameTypeId(NULL, targettype);
+					Oid	 sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+					Oid	 targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
 
 					address.classId = CastRelationId;
 					address.objectId =
@@ -942,26 +942,30 @@ get_object_address_relobject(ObjectType
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_ok);
+
+		reloid = (relation != NULL) ? RelationGetRelid(relation) : InvalidOid;
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			default:
@@ -975,7 +979,9 @@ get_object_address_relobject(ObjectType
 		/* Avoid relcache leak when object not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			heap_close(relation, AccessShareLock);
+			if (relation != NULL)
+				heap_close(relation, AccessShareLock);
+
 			relation = NULL;	/* department of accident prevention */
 			return address;
 		}
@@ -1052,7 +1058,7 @@ get_object_address_type(ObjectType objty
 	address.objectId = InvalidOid;
 	address.objectSubId = 0;
 
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, missing_ok);
 	if (!HeapTupleIsValid(tup))
 	{
 		if (!missing_ok)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
new file mode 100644
index b32ad3a..d7a0f82
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -32,6 +32,15 @@
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
 
+static bool parent_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name);
+
+static bool schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name);
+
+
 /*
  * Drop one or more objects.
  *
@@ -125,6 +134,63 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * For triggers and rules, test if the parent relation exists.  If it does not,
+ * report it as missing rather than reporting the trigger or rule as missing.
+ * This is used for DROP RULE/TRIGGER IF EXISTS.
+ */
+static bool
+parent_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	List	   *parent_objname;
+	RangeVar   *parent_rel;
+
+	parent_objname = list_truncate(list_copy(objname),
+								   list_length(objname) - 1);
+
+	if (schema_does_not_exist_skipping(parent_objname, msg, name))
+		return true;
+
+	parent_rel = makeRangeVarFromNameList(parent_objname);
+
+	if (!OidIsValid(RangeVarGetRelid(parent_rel, NoLock, true)))
+	{
+		*msg = gettext_noop("relation \"%s\" does not exist, skipping");
+		*name = NameListToString(parent_objname);
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * If a schema was explicitly specified, test if it exists.  If it does not,
+ * report the schema as missing rather than the child object.
+ */
+static bool
+schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(objname);
+
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exist, skipping");
+		*name = rel->schemaname;
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
  * get_object_address() will throw an ERROR.
@@ -140,81 +206,126 @@ does_not_exist_skipping(ObjectType objty
 	{
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			msg = gettext_noop("type \"%s\" does not exist, skipping");
-			name = TypeNameToString(makeTypeNameFromNameList(objname));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("type \"%s\" does not exist, skipping");
+				name = TypeNameToString(makeTypeNameFromNameList(objname));
+			}
 			break;
 		case OBJECT_COLLATION:
-			msg = gettext_noop("collation \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("collation \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_CONVERSION:
-			msg = gettext_noop("conversion \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_SCHEMA:
 			msg = gettext_noop("schema \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_TSPARSER:
-			msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSDICTIONARY:
-			msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSTEMPLATE:
-			msg = gettext_noop("text search template \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSCONFIGURATION:
-			msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_EXTENSION:
 			msg = gettext_noop("extension \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_FUNCTION:
-			msg = gettext_noop("function %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("function %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_AGGREGATE:
-			msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_OPERATOR:
-			msg = gettext_noop("operator %s does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator %s does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_LANGUAGE:
 			msg = gettext_noop("language \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_CAST:
-			msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
-			name = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objname)));
-			args = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objargs)));
+			{
+				TypeName *tobjname = (TypeName *) linitial(objname);
+				TypeName *targname = (TypeName *) linitial(objargs);
+
+				if (!schema_does_not_exist_skipping(tobjname->names,
+													&msg, &name) &&
+					!schema_does_not_exist_skipping(targname->names,
+													&msg, &name))
+				{
+					msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+					name = TypeNameToString(tobjname);
+					args = TypeNameToString(targname);
+				}
+			}
 			break;
 		case OBJECT_TRIGGER:
-			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			if (!parent_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
+				name = strVal(llast(objname));
+				args = NameListToString(list_truncate(list_copy(objname),
+													  list_length(objname) - 1));
+			}
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_RULE:
-			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			if (!parent_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
+				name = strVal(llast(objname));
+				args = NameListToString(list_truncate(list_copy(objname),
+													  list_length(objname) - 1));
+			}
 			break;
 		case OBJECT_FDW:
 			msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
@@ -225,14 +336,20 @@ does_not_exist_skipping(ObjectType objty
 			name = NameListToString(objname);
 			break;
 		case OBJECT_OPCLASS:
-			msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		case OBJECT_OPFAMILY:
-			msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		default:
 			elog(ERROR, "unexpected object type (%d)", (int) objtype);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
new file mode 100644
index ca754b4..348b901
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -86,7 +86,7 @@ compute_return_type(TypeName *returnType
 	Type		typtup;
 	AclResult	aclresult;
 
-	typtup = LookupTypeName(NULL, returnType, NULL);
+	typtup = LookupTypeName(NULL, returnType, NULL, false);
 
 	if (typtup)
 	{
@@ -220,7 +220,7 @@ interpret_function_parameter_list(List *
 		Type		typtup;
 		AclResult	aclresult;
 
-		typtup = LookupTypeName(NULL, t, NULL);
+		typtup = LookupTypeName(NULL, t, NULL, false);
 		if (typtup)
 		{
 			if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3140b37..576f7b1
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -103,11 +103,14 @@ OpFamilyCacheLookup(Oid amID, List *opfa
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(OPFAMILYAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opfname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(OPFAMILYAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opfname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
@@ -179,11 +182,14 @@ OpClassCacheLookup(Oid amID, List *opcla
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(CLAAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opcname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(CLAAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opcname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 1aa1ad9..f2789d0
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -690,10 +690,28 @@ DefineRelation(CreateStmt *stmt, char re
  * non-existent relation
  */
 static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
 {
 	const struct dropmsgstrings *rentry;
 
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		if (!missing_ok)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_SCHEMA),
+					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
+		}
+		else
+		{
+			ereport(NOTICE,
+					(errmsg("schema \"%s\" does not exist, skipping",
+							rel->schemaname)));
+		}
+		return;
+	}
+
 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
 	{
 		if (rentry->kind == rightkind)
@@ -702,11 +720,11 @@ DropErrorMsgNonExistent(const char *reln
 			{
 				ereport(ERROR,
 						(errcode(rentry->nonexistent_code),
-						 errmsg(rentry->nonexistent_msg, relname)));
+						 errmsg(rentry->nonexistent_msg, rel->relname)));
 			}
 			else
 			{
-				ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
+				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
 				break;
 			}
 		}
@@ -845,7 +863,7 @@ RemoveRelations(DropStmt *drop)
 		/* Not there? */
 		if (!OidIsValid(relOid))
 		{
-			DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
 			continue;
 		}
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
new file mode 100644
index d4a14ca..4805f2b
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3245,7 +3245,7 @@ AlterTypeOwner(List *names, Oid newOwner
 	typename = makeTypeNameFromNameList(names);
 
 	/* Use LookupTypeName here so that shell types can be processed */
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
new file mode 100644
index ede36d1..f560b48
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1062,7 +1062,8 @@ func_get_detail(List *funcname,
 
 	/* Get list of possible candidates from namespace search */
 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
-										   expand_variadic, expand_defaults);
+										   expand_variadic, expand_defaults,
+													   false);
 
 	/*
 	 * Quickly check if there is an exact match to the input datatypes (there
@@ -1422,7 +1423,7 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
 	if (typtup == NULL)
 		return InvalidOid;
 
@@ -1581,7 +1582,7 @@ LookupFuncName(List *funcname, int nargs
 {
 	FuncCandidateList clist;
 
-	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
 
 	while (clist)
 	{
@@ -1601,27 +1602,6 @@ LookupFuncName(List *funcname, int nargs
 }
 
 /*
- * LookupTypeNameOid
- *		Convenience routine to look up a type, silently accepting shell types
- */
-static Oid
-LookupTypeNameOid(const TypeName *typename)
-{
-	Oid			result;
-	Type		typtup;
-
-	typtup = LookupTypeName(NULL, typename, NULL);
-	if (typtup == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename))));
-	result = typeTypeId(typtup);
-	ReleaseSysCache(typtup);
-	return result;
-}
-
-/*
  * LookupFuncNameTypeNames
  *		Like LookupFuncName, but the argument types are specified by a
  *		list of TypeName nodes.
@@ -1648,7 +1628,7 @@ LookupFuncNameTypeNames(List *funcname,
 	{
 		TypeName   *t = (TypeName *) lfirst(args_item);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		args_item = lnext(args_item);
 	}
 
@@ -1688,7 +1668,7 @@ LookupAggNameTypeNames(List *aggname, Li
 	{
 		TypeName   *t = (TypeName *) lfirst(lc);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		i++;
 	}
 
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
new file mode 100644
index dd80fa9..9595f10
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -103,7 +103,7 @@ LookupOperName(ParseState *pstate, List
 {
 	Oid			result;
 
-	result = OpernameGetOprid(opername, oprleft, oprright);
+	result = OpernameGetOprid(opername, oprleft, oprright, noError);
 	if (OidIsValid(result))
 		return result;
 
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *psta
 	if (oprleft == NULL)
 		leftoid = InvalidOid;
 	else
-		leftoid = typenameTypeId(pstate, oprleft);
+		leftoid = LookupTypeNameOid(pstate, oprleft, noError);
 
 	if (oprright == NULL)
 		rightoid = InvalidOid;
 	else
-		rightoid = typenameTypeId(pstate, oprright);
+		rightoid = LookupTypeNameOid(pstate, oprright, noError);
 
 	return LookupOperName(pstate, opername, leftoid, rightoid,
 						  noError, location);
@@ -280,7 +280,7 @@ binary_oper_exact(List *opname, Oid arg1
 		was_unknown = true;
 	}
 
-	result = OpernameGetOprid(opname, arg1, arg2);
+	result = OpernameGetOprid(opname, arg1, arg2, false);
 	if (OidIsValid(result))
 		return result;
 
@@ -291,7 +291,7 @@ binary_oper_exact(List *opname, Oid arg1
 
 		if (basetype != arg1)
 		{
-			result = OpernameGetOprid(opname, basetype, basetype);
+			result = OpernameGetOprid(opname, basetype, basetype, false);
 			if (OidIsValid(result))
 				return result;
 		}
@@ -544,7 +544,7 @@ right_oper(ParseState *pstate, List *op,
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
+	operOid = OpernameGetOprid(op, arg, InvalidOid, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
@@ -622,7 +622,7 @@ left_oper(ParseState *pstate, List *op,
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, InvalidOid, arg);
+	operOid = OpernameGetOprid(op, InvalidOid, arg, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
new file mode 100644
index ee6802a..c72fc8d
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -56,7 +56,8 @@ static int32 typenameTypeMod(ParseState
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p)
+			   int32 *typmod_p,
+					bool missing_ok)
 {
 	Oid			typoid;
 	HeapTuple	tup;
@@ -116,15 +117,21 @@ LookupTypeName(ParseState *pstate, const
 		 * concurrent DDL.	But taking a lock would carry a performance
 		 * penalty and would also require a permissions check.
 		 */
-		relid = RangeVarGetRelid(rel, NoLock, false);
-		attnum = get_attnum(relid, field);
-		if (attnum == InvalidAttrNumber)
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_COLUMN),
-					 errmsg("column \"%s\" of relation \"%s\" does not exist",
-							field, rel->relname),
-					 parser_errposition(pstate, typeName->location)));
-		typoid = get_atttype(relid, attnum);
+		typoid = InvalidOid;
+		relid = RangeVarGetRelid(rel, NoLock, missing_ok);
+
+		if (OidIsValid(relid))
+		{
+			attnum = get_attnum(relid, field);
+			if (attnum != InvalidAttrNumber)
+				typoid = get_atttype(relid, attnum);
+			else if (!missing_ok)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_COLUMN),
+						 errmsg("column \"%s\" of relation \"%s\" does not exist",
+								field, rel->relname),
+						 parser_errposition(pstate, typeName->location)));
+		}
 
 		/* this construct should never have an array indicator */
 		Assert(typeName->arrayBounds == NIL);
@@ -149,10 +156,13 @@ LookupTypeName(ParseState *pstate, const
 			/* Look in specific schema only */
 			Oid			namespaceId;
 
-			namespaceId = LookupExplicitNamespace(schemaname, false);
-			typoid = GetSysCacheOid2(TYPENAMENSP,
+			namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+			if (OidIsValid(namespaceId))
+				typoid = GetSysCacheOid2(TYPENAMENSP,
 									 PointerGetDatum(typname),
 									 ObjectIdGetDatum(namespaceId));
+			else
+				typoid = InvalidOid;
 		}
 		else
 		{
@@ -196,7 +206,7 @@ typenameType(ParseState *pstate, const T
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typeName, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -228,6 +238,35 @@ typenameTypeId(ParseState *pstate, const
 	typoid = HeapTupleGetOid(tup);
 	ReleaseSysCache(tup);
 
+	return typoid;
+}
+
+/*
+ * returns oid of type
+ *		Convenience routine to look up a type, silently accepting shell types
+ */
+Oid
+LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
+{
+	Oid			typoid;
+	Type		tup;
+
+	tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
+	if (tup == NULL)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typeName)),
+					 parser_errposition(pstate, typeName->location)));
+
+		return InvalidOid;
+	}
+
+	typoid = HeapTupleGetOid(tup);
+	ReleaseSysCache(tup);
+
 	return typoid;
 }
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
new file mode 100644
index c24a2c1..28c1e7f
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -135,7 +135,7 @@ regprocin(PG_FUNCTION_ARGS)
 	 * pg_proc entries in the current search path.
 	 */
 	names = stringToQualifiedNameList(pro_name_or_oid);
-	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
+	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
 
 	if (clist == NULL)
 		ereport(ERROR,
@@ -192,7 +192,7 @@ regprocout(PG_FUNCTION_ARGS)
 			 * qualify it.
 			 */
 			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-										  -1, NIL, false, false);
+										  -1, NIL, false, false, false);
 			if (clist != NULL && clist->next == NULL &&
 				clist->oid == proid)
 				nspname = NULL;
@@ -279,7 +279,7 @@ regprocedurein(PG_FUNCTION_ARGS)
 	 */
 	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
 
-	clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
 
 	for (; clist; clist = clist->next)
 	{
@@ -661,7 +661,7 @@ regoperatorin(PG_FUNCTION_ARGS)
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
 
-	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
+	result = OpernameGetOprid(names, argtypes[0], argtypes[1], false);
 
 	if (!OidIsValid(result))
 		ereport(ERROR,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
new file mode 100644
index 4fadc74..05c035b
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -71,10 +71,11 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names,
 					  int nargs, List *argnames,
 					  bool expand_variadic,
-					  bool expand_defaults);
+					  bool expand_defaults,
+					  bool noError);
 extern bool FunctionIsVisible(Oid funcid);
 
-extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
+extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
new file mode 100644
index 340121a..51da025
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,7 +20,9 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p);
+			   int32 *typmod_p, bool missing_ok);
+extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
+				 bool missing_ok);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
 extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
new file mode 100644
index 426aeb5..692bba4
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1665,7 +1665,7 @@ plpgsql_parse_wordtype(char *ident)
 	 * Word wasn't found in the namespace stack. Try to find a data type with
 	 * that name, but ignore shell types and complex types.
 	 */
-	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, false);
 	if (typeTup)
 	{
 		Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
new file mode 100644
index 8599401..66dcb00
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -169,11 +169,15 @@ NOTICE:  cast from type text to type tex
 DROP TRIGGER test_trigger_exists ON test_exists;
 ERROR:  trigger "test_trigger_exists" for table "test_exists" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
-NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, skipping
+NOTICE:  trigger "test_trigger_exists" for relation "test_exists" does not exist, skipping
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for rel
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -223,3 +231,48 @@ ERROR:  access method "no_such_am" does
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
 ERROR:  table "test_exists" does not exist
+-- be toleralnt with not existing schema
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
new file mode 100644
index 656d47f..d4723b2
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -280,7 +280,7 @@ SELECT * FROM dropped_objects WHERE sche
 (23 rows)
 
 DROP OWNED BY regression_bob;
-NOTICE:  table "audit_tbls_schema_one_table_two" does not exist, skipping
+NOTICE:  schema "audit_tbls" does not exist, skipping
 CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
new file mode 100644
index 6330566..a2f265d
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exis
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -226,3 +232,28 @@ DROP OPERATOR FAMILY IF EXISTS test_oper
 DROP TABLE IF EXISTS test_exists;
 
 DROP TABLE test_exists;
+
+-- be toleralnt with not existing schema
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+DROP COLLATION IF EXISTS no_such_schema.foo;
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+DROP INDEX IF EXISTS no_such_schema.foo;
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+DROP TABLE IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+DROP TYPE IF EXISTS no_such_schema.foo;
+DROP VIEW IF EXISTS no_such_schema.foo;
#65Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#64)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

it looks well, thank you

Regards

Pavel

2013/12/1 Dean Rasheed <dean.a.rasheed@gmail.com>

Show quoted text

On 1 December 2013 07:32, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2013/11/30 Peter Eisentraut <peter_e@gmx.net>

trailing whitespace

fixed,

Hi,

I've been looking at this and I think it's mostly in good shape, but I
spotted a few minor issues:

* There's a typo in the notice text in a couple of places --- "does
not exists, skipping" should be "does not exist, skipping".

* In does_not_exist_skipping(), the schema existence checks for
extensions and foreign data wrappers are not necessary, since I don't
think they can be schema-qualified.

* Also in does_not_exist_skipping(), in the block for casts, it is no
longer safe to use format_type_be() because it is now possible for the
types to not exist at this point. So I think it needs to use
TypeNameToString() there instead, otherwise it might raise a no such
type ERROR while trying to issue the NOTICE.

* In DropErrorMsgNonExistent(), I think the ERROR text should report
no such schema in the same way as the NOTICE text when the schema
doesn't exist for consistency with the other ERRORs and NOTICEs.

* Some more code is needed to make DROP OPERATOR FAMILY IF EXISTS
tolerate a non-existent schema.

Attached is an updated patch for those issues. I also tried to tidy up
the code in dropcmds.c a bit, removing some duplicated code, and
making parent_does_not_exist_skipping() have the same signature as
schema_does_not_exist_skipping(). This makes the code in
does_not_exist_skipping() a little neater, and means that
parent_does_not_exist_skipping() can just call
schema_does_not_exist_skipping() to check for the existence of the
parent relation's schema.

I hope those changes are all OK.

Regards,
Dean

#66Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Dean Rasheed (#64)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Dean Rasheed escribi�:

+/*
+ * If a schema was explicitly specified, test if it exists.  If it does not,
+ * report the schema as missing rather than the child object.
+ */
+static bool
+schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(objname);
+
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exist, skipping");
+		*name = rel->schemaname;
+
+		return true;
+	}
+
+	return false;
+}

In success cases, are we leaking a lot of memory? In the error case I
guess it doesn't matter that the RangeVar is getting leaked (we're
aborting anyway), but if we're called and everything turns out to work,
are things cleaned up timely?

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#67Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Alvaro Herrera (#66)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2 December 2013 19:37, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Dean Rasheed escribió:

+/*
+ * If a schema was explicitly specified, test if it exists.  If it does not,
+ * report the schema as missing rather than the child object.
+ */
+static bool
+schema_does_not_exist_skipping(List *objname,
+                                                        const char **msg,
+                                                        char **name)
+{
+     RangeVar        *rel;
+
+     rel = makeRangeVarFromNameList(objname);
+
+     if (rel->schemaname != NULL &&
+             !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+     {
+             *msg = gettext_noop("schema \"%s\" does not exist, skipping");
+             *name = rel->schemaname;
+
+             return true;
+     }
+
+     return false;
+}

In success cases, are we leaking a lot of memory? In the error case I
guess it doesn't matter that the RangeVar is getting leaked (we're
aborting anyway), but if we're called and everything turns out to work,
are things cleaned up timely?

I think that memory gets freed at the end of the DROP command, so I
don't think this is a concern. In any case, that RangeVar is only of
order 50 bytes. If we were concerned about memory leakage here, a
bigger concern would be the calling code in does_not_exist_skipping(),
which is using NameListToString() which allocates at least 1024 bytes
for the name of the non-existent object without freeing it.

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#68Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Dean Rasheed (#67)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Dean Rasheed escribi�:

I think that memory gets freed at the end of the DROP command, so I
don't think this is a concern. In any case, that RangeVar is only of
order 50 bytes. If we were concerned about memory leakage here, a
bigger concern would be the calling code in does_not_exist_skipping(),
which is using NameListToString() which allocates at least 1024 bytes
for the name of the non-existent object without freeing it.

Fair enough.

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#69Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#63)
Re: Fwd: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 12/1/13, 2:32 AM, Pavel Stehule wrote:

trailing whitespace

fixed,

Peter, what application do you use for this check?

git diff --check

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#70Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Pavel Stehule (#65)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 2 December 2013 04:55, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hello

it looks well, thank you

Regards

Pavel

I've been thinking about this some more, and there's another case that
concerns me slightly. We're now making some of the DROP...IF EXISTS
commands tolerate non-existent types as well as non-existent schemas
--- functions, aggregates, casts and operators all have type names in
their specifications. Of course it's possible that the type is missing
because it was in a schema that was dropped, so this change seems to
be in spirit of what was discussed, but it seems like a change that
might catch some people out.

I think that, on balance, it is a sensible change, since if the type
doesn't exist, the dependent object can't exist either, so DROP...IF
EXISTS shouldn't be raising an error. However, I wonder if we should
be issuing a more specific NOTICE in this case too --- i.e., check for
non-existent types in the same way as we check for non-existent parent
objects --- type_does_not_exist_skipping() and
type_list_does_not_exist_skipping().

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#71Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#70)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/12/4 Dean Rasheed <dean.a.rasheed@gmail.com>

On 2 December 2013 04:55, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hello

it looks well, thank you

Regards

Pavel

I've been thinking about this some more, and there's another case that
concerns me slightly. We're now making some of the DROP...IF EXISTS
commands tolerate non-existent types as well as non-existent schemas
--- functions, aggregates, casts and operators all have type names in
their specifications. Of course it's possible that the type is missing
because it was in a schema that was dropped, so this change seems to
be in spirit of what was discussed, but it seems like a change that
might catch some people out.

I think that, on balance, it is a sensible change, since if the type
doesn't exist, the dependent object can't exist either, so DROP...IF
EXISTS shouldn't be raising an error. However, I wonder if we should
be issuing a more specific NOTICE in this case too --- i.e., check for
non-existent types in the same way as we check for non-existent parent
objects --- type_does_not_exist_skipping() and
type_list_does_not_exist_skipping().

+1

Pavel

Show quoted text

Regards,
Dean

#72Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#71)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Can someone in this thread clarify the commit fest situation? I see two
entries that appear to be the same:

https://commitfest.postgresql.org/action/patch_view?id=1174
https://commitfest.postgresql.org/action/patch_view?id=1175

I think the first one is a duplicate or obsolete.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#73Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Peter Eisentraut (#72)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 5 December 2013 01:33, Peter Eisentraut <peter_e@gmx.net> wrote:

Can someone in this thread clarify the commit fest situation? I see two
entries that appear to be the same:

https://commitfest.postgresql.org/action/patch_view?id=1174
https://commitfest.postgresql.org/action/patch_view?id=1175

I think the first one is a duplicate or obsolete.

#1174 looks to be a separate feature. I don't think it's dependent on
#1175 from a code standpoint, but it probably needs it to work
properly in all situations.

I think #1175 is close to being ready for commit. Pavel, will you
produce an updated patch based on our last discussion? I'll set this
patch to waiting on author.

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#74Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#72)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/12/5 Peter Eisentraut <peter_e@gmx.net>

Can someone in this thread clarify the commit fest situation? I see two
entries that appear to be the same:

https://commitfest.postgresql.org/action/patch_view?id=1174
https://commitfest.postgresql.org/action/patch_view?id=1175

I think the first one is a duplicate or obsolete.

no, both are valid, and every solve different issue.

https://commitfest.postgresql.org/action/patch_view?id=1175

it implements fully fault tolerant DROP IF EXISTS statements. This patch is
prerequisite for second patch

https://commitfest.postgresql.org/action/patch_view?id=1174

This is a implementation of new pg_dump option --if-exists. This option
ensure using fault tolerant DROPs statement by dump.

Regards

Pavel

#75Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#73)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/12/5 Dean Rasheed <dean.a.rasheed@gmail.com>

On 5 December 2013 01:33, Peter Eisentraut <peter_e@gmx.net> wrote:

Can someone in this thread clarify the commit fest situation? I see two
entries that appear to be the same:

https://commitfest.postgresql.org/action/patch_view?id=1174
https://commitfest.postgresql.org/action/patch_view?id=1175

I think the first one is a duplicate or obsolete.

#1174 looks to be a separate feature. I don't think it's dependent on
#1175 from a code standpoint, but it probably needs it to work
properly in all situations.

I think #1175 is close to being ready for commit. Pavel, will you
produce an updated patch based on our last discussion? I'll set this
patch to waiting on author.

I expected so your version was a final. I have no problem to do other
enhancing (by me) , but I don't fully understand to your last proposal. Can
you specify it more, please?

Regards

Pavel

Show quoted text

Regards,
Dean

#76Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Pavel Stehule (#75)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 5 December 2013 10:06, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I think #1175 is close to being ready for commit. Pavel, will you
produce an updated patch based on our last discussion? I'll set this
patch to waiting on author.

I expected so your version was a final. I have no problem to do other
enhancing (by me) , but I don't fully understand to your last proposal. Can
you specify it more, please?

Well I was basically proposing that does_not_exist_skipping() be
enhanced to report on non-existent types that form part of the object
specification. I think this would affect the CAST, FUNCTION, AGGREGATE
and OPERATOR cases, but should be a fairly trivial extension to the
code that you've already added.

It should be possible to make the notice text from DROP...IF EXISTS
consistent with the error text from a plain DROP. For example consider
cases like func_name(no_such_schema.typename) and
func_name(existing_schema.no_such_type).

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#77Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#76)
1 attachment(s)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2013/12/5 Dean Rasheed <dean.a.rasheed@gmail.com>

On 5 December 2013 10:06, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I think #1175 is close to being ready for commit. Pavel, will you
produce an updated patch based on our last discussion? I'll set this
patch to waiting on author.

I expected so your version was a final. I have no problem to do other
enhancing (by me) , but I don't fully understand to your last proposal.

Can

you specify it more, please?

Well I was basically proposing that does_not_exist_skipping() be
enhanced to report on non-existent types that form part of the object
specification. I think this would affect the CAST, FUNCTION, AGGREGATE
and OPERATOR cases, but should be a fairly trivial extension to the
code that you've already added.

ok, updated patch is in attachment

It should be possible to make the notice text from DROP...IF EXISTS
consistent with the error text from a plain DROP. For example consider
cases like func_name(no_such_schema.typename) and
func_name(existing_schema.no_such_type).

yes, it is possible, but I wouldn't enhance a scope of this patch, if it is
possible, please. I would to finish a --if-exist option for pg_dump a
pg_restore before (in this release cycle).

We can continue in cleaning DROP obj messages in next release, or maybe in
last commitfest - this functionality is not critical and is not complex.

Regards

Pavel

Show quoted text

Regards,
Dean

Attachments:

drop-if-exists-consistency-v3.patchtext/x-patch; charset=US-ASCII; name=drop-if-exists-consistency-v3.patchDownload
commit cc4e8a0f3431fa286f687e473123c55a92c0e707
Author: Pavel Stehule <pavel.stehule@gmail.com>
Date:   Sat Dec 7 22:26:48 2013 +0100

    fully fault tolerant if exists consistent drop obj

diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 4434dd6..b32f2e4 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -909,7 +909,7 @@ TypeIsVisible(Oid typid)
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-					  bool expand_variadic, bool expand_defaults)
+					  bool expand_variadic, bool expand_defaults, bool noError)
 {
 	FuncCandidateList resultList = NULL;
 	bool		any_special = false;
@@ -928,7 +928,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 	if (schemaname)
 	{
 		/* use exact schema given */
-		namespaceId = LookupExplicitNamespace(schemaname, false);
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (!OidIsValid(namespaceId))
+			return NULL;
 	}
 	else
 	{
@@ -1414,7 +1416,7 @@ FunctionIsVisible(Oid funcid)
 		visible = false;
 
 		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-									  nargs, NIL, false, false);
+									  nargs, NIL, false, false, false);
 
 		for (; clist; clist = clist->next)
 		{
@@ -1446,7 +1448,7 @@ FunctionIsVisible(Oid funcid)
  * namespace search path.
  */
 Oid
-OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError)
 {
 	char	   *schemaname;
 	char	   *opername;
@@ -1462,18 +1464,21 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
 		Oid			namespaceId;
 		HeapTuple	opertup;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		opertup = SearchSysCache4(OPERNAMENSP,
-								  CStringGetDatum(opername),
-								  ObjectIdGetDatum(oprleft),
-								  ObjectIdGetDatum(oprright),
-								  ObjectIdGetDatum(namespaceId));
-		if (HeapTupleIsValid(opertup))
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (OidIsValid(namespaceId))
 		{
-			Oid			result = HeapTupleGetOid(opertup);
+			opertup = SearchSysCache4(OPERNAMENSP,
+									  CStringGetDatum(opername),
+									  ObjectIdGetDatum(oprleft),
+									  ObjectIdGetDatum(oprright),
+									  ObjectIdGetDatum(namespaceId));
+			if (HeapTupleIsValid(opertup))
+			{
+				Oid			result = HeapTupleGetOid(opertup);
 
-			ReleaseSysCache(opertup);
-			return result;
+				ReleaseSysCache(opertup);
+				return result;
+			}
 		}
 		return InvalidOid;
 	}
@@ -1734,7 +1739,8 @@ OperatorIsVisible(Oid oprid)
 		char	   *oprname = NameStr(oprform->oprname);
 
 		visible = (OpernameGetOprid(list_make1(makeString(oprname)),
-									oprform->oprleft, oprform->oprright)
+									oprform->oprleft, oprform->oprright,
+											   false)
 				   == oprid);
 	}
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 9011190..6a851fa 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -580,8 +580,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				{
 					TypeName   *sourcetype = (TypeName *) linitial(objname);
 					TypeName   *targettype = (TypeName *) linitial(objargs);
-					Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
-					Oid			targettypeid = typenameTypeId(NULL, targettype);
+					Oid	 sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+					Oid	 targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
 
 					address.classId = CastRelationId;
 					address.objectId =
@@ -942,26 +942,30 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_ok);
+
+		reloid = (relation != NULL) ? RelationGetRelid(relation) : InvalidOid;
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			default:
@@ -975,7 +979,9 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 		/* Avoid relcache leak when object not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			heap_close(relation, AccessShareLock);
+			if (relation != NULL)
+				heap_close(relation, AccessShareLock);
+
 			relation = NULL;	/* department of accident prevention */
 			return address;
 		}
@@ -1052,7 +1058,7 @@ get_object_address_type(ObjectType objtype,
 	address.objectId = InvalidOid;
 	address.objectSubId = 0;
 
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, missing_ok);
 	if (!HeapTupleIsValid(tup))
 	{
 		if (!missing_ok)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..404a893 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -32,6 +32,17 @@
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
 
+static bool parent_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name);
+
+static bool schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name);
+static bool type_in_list_does_not_exist_skipping(List *typenames,
+							   const char **msg,
+							   char **name);
+
 /*
  * Drop one or more objects.
  *
@@ -125,6 +136,100 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * For triggers and rules, test if the parent relation exists.  If it does not,
+ * report it as missing rather than reporting the trigger or rule as missing.
+ * This is used for DROP RULE/TRIGGER IF EXISTS.
+ */
+static bool
+parent_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	List	   *parent_objname;
+	RangeVar   *parent_rel;
+
+	parent_objname = list_truncate(list_copy(objname),
+								   list_length(objname) - 1);
+
+	if (schema_does_not_exist_skipping(parent_objname, msg, name))
+		return true;
+
+	parent_rel = makeRangeVarFromNameList(parent_objname);
+
+	if (!OidIsValid(RangeVarGetRelid(parent_rel, NoLock, true)))
+	{
+		*msg = gettext_noop("relation \"%s\" does not exist, skipping");
+		*name = NameListToString(parent_objname);
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * If a schema was explicitly specified, test if it exists.  If it does not,
+ * report the schema as missing rather than the child object.
+ */
+static bool
+schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(objname);
+
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exist, skipping");
+		*name = rel->schemaname;
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * For functions, casts, aggregates and operators check used datatypes.
+ * report a type as missing instead a master object.
+ *
+ * First parameter is a list of TypeNames.
+ */
+static bool
+type_in_list_does_not_exist_skipping(List *typenames,
+							   const char **msg,
+							   char **name)
+{
+	ListCell   *l;
+
+	foreach(l, typenames)
+	{
+		TypeName *typeName = (TypeName *) lfirst(l);
+
+		Assert(IsA(typeName, TypeName));
+
+		if  (!OidIsValid(LookupTypeNameOid(NULL, typeName, true)))
+		{
+			/* type doesn't exist, try to find why */
+			if (schema_does_not_exist_skipping(typeName->names,
+									msg, name))
+				return true;
+
+			*msg = gettext_noop("type \"%s\" does not exist, skipping");
+			*name = TypeNameToString(typeName);
+
+			return true;
+		}
+
+	}
+
+	return false;
+}
+
+/*
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
  * get_object_address() will throw an ERROR.
@@ -140,81 +245,124 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			msg = gettext_noop("type \"%s\" does not exist, skipping");
-			name = TypeNameToString(makeTypeNameFromNameList(objname));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("type \"%s\" does not exist, skipping");
+				name = TypeNameToString(makeTypeNameFromNameList(objname));
+			}
 			break;
 		case OBJECT_COLLATION:
-			msg = gettext_noop("collation \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("collation \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_CONVERSION:
-			msg = gettext_noop("conversion \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_SCHEMA:
 			msg = gettext_noop("schema \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_TSPARSER:
-			msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSDICTIONARY:
-			msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSTEMPLATE:
-			msg = gettext_noop("text search template \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSCONFIGURATION:
-			msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_EXTENSION:
 			msg = gettext_noop("extension \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_FUNCTION:
-			msg = gettext_noop("function %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name)
+				   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+			{
+				msg = gettext_noop("function %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_AGGREGATE:
-			msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name)
+				   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+			{
+				msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_OPERATOR:
-			msg = gettext_noop("operator %s does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name)
+				   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+			{
+				msg = gettext_noop("operator %s does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_LANGUAGE:
 			msg = gettext_noop("language \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_CAST:
-			msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
-			name = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objname)));
-			args = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objargs)));
+			{
+				if (!type_in_list_does_not_exist_skipping(objname, &msg, &name)
+					   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+				{
+					msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+					name = TypeNameToString((TypeName *) linitial(objname));
+					args = TypeNameToString((TypeName *) linitial(objargs));
+				}
+			}
 			break;
 		case OBJECT_TRIGGER:
-			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			if (!parent_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
+				name = strVal(llast(objname));
+				args = NameListToString(list_truncate(list_copy(objname),
+													  list_length(objname) - 1));
+			}
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_RULE:
-			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			if (!parent_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
+				name = strVal(llast(objname));
+				args = NameListToString(list_truncate(list_copy(objname),
+													  list_length(objname) - 1));
+			}
 			break;
 		case OBJECT_FDW:
 			msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
@@ -225,14 +373,20 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 			name = NameListToString(objname);
 			break;
 		case OBJECT_OPCLASS:
-			msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		case OBJECT_OPFAMILY:
-			msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		default:
 			elog(ERROR, "unexpected object type (%d)", (int) objtype);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ca754b4..348b901 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -86,7 +86,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
 	Type		typtup;
 	AclResult	aclresult;
 
-	typtup = LookupTypeName(NULL, returnType, NULL);
+	typtup = LookupTypeName(NULL, returnType, NULL, false);
 
 	if (typtup)
 	{
@@ -220,7 +220,7 @@ interpret_function_parameter_list(List *parameters,
 		Type		typtup;
 		AclResult	aclresult;
 
-		typtup = LookupTypeName(NULL, t, NULL);
+		typtup = LookupTypeName(NULL, t, NULL, false);
 		if (typtup)
 		{
 			if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 3140b37..576f7b1 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -103,11 +103,14 @@ OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(OPFAMILYAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opfname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(OPFAMILYAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opfname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
@@ -179,11 +182,14 @@ OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(CLAAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opcname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(CLAAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opcname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1d9f29a..2a7ab51 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -690,10 +690,28 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  * non-existent relation
  */
 static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
 {
 	const struct dropmsgstrings *rentry;
 
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		if (!missing_ok)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_SCHEMA),
+					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
+		}
+		else
+		{
+			ereport(NOTICE,
+					(errmsg("schema \"%s\" does not exist, skipping",
+							rel->schemaname)));
+		}
+		return;
+	}
+
 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
 	{
 		if (rentry->kind == rightkind)
@@ -702,11 +720,11 @@ DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
 			{
 				ereport(ERROR,
 						(errcode(rentry->nonexistent_code),
-						 errmsg(rentry->nonexistent_msg, relname)));
+						 errmsg(rentry->nonexistent_msg, rel->relname)));
 			}
 			else
 			{
-				ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
+				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
 				break;
 			}
 		}
@@ -845,7 +863,7 @@ RemoveRelations(DropStmt *drop)
 		/* Not there? */
 		if (!OidIsValid(relOid))
 		{
-			DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
 			continue;
 		}
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..4805f2b 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3245,7 +3245,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 	typename = makeTypeNameFromNameList(names);
 
 	/* Use LookupTypeName here so that shell types can be processed */
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index ede36d1..f560b48 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1062,7 +1062,8 @@ func_get_detail(List *funcname,
 
 	/* Get list of possible candidates from namespace search */
 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
-										   expand_variadic, expand_defaults);
+										   expand_variadic, expand_defaults,
+													   false);
 
 	/*
 	 * Quickly check if there is an exact match to the input datatypes (there
@@ -1422,7 +1423,7 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
 	if (typtup == NULL)
 		return InvalidOid;
 
@@ -1581,7 +1582,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 {
 	FuncCandidateList clist;
 
-	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
 
 	while (clist)
 	{
@@ -1601,27 +1602,6 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 }
 
 /*
- * LookupTypeNameOid
- *		Convenience routine to look up a type, silently accepting shell types
- */
-static Oid
-LookupTypeNameOid(const TypeName *typename)
-{
-	Oid			result;
-	Type		typtup;
-
-	typtup = LookupTypeName(NULL, typename, NULL);
-	if (typtup == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename))));
-	result = typeTypeId(typtup);
-	ReleaseSysCache(typtup);
-	return result;
-}
-
-/*
  * LookupFuncNameTypeNames
  *		Like LookupFuncName, but the argument types are specified by a
  *		list of TypeName nodes.
@@ -1648,7 +1628,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
 	{
 		TypeName   *t = (TypeName *) lfirst(args_item);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		args_item = lnext(args_item);
 	}
 
@@ -1688,7 +1668,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
 	{
 		TypeName   *t = (TypeName *) lfirst(lc);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		i++;
 	}
 
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index dd80fa9..9595f10 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -103,7 +103,7 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 {
 	Oid			result;
 
-	result = OpernameGetOprid(opername, oprleft, oprright);
+	result = OpernameGetOprid(opername, oprleft, oprright, noError);
 	if (OidIsValid(result))
 		return result;
 
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername,
 	if (oprleft == NULL)
 		leftoid = InvalidOid;
 	else
-		leftoid = typenameTypeId(pstate, oprleft);
+		leftoid = LookupTypeNameOid(pstate, oprleft, noError);
 
 	if (oprright == NULL)
 		rightoid = InvalidOid;
 	else
-		rightoid = typenameTypeId(pstate, oprright);
+		rightoid = LookupTypeNameOid(pstate, oprright, noError);
 
 	return LookupOperName(pstate, opername, leftoid, rightoid,
 						  noError, location);
@@ -280,7 +280,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 		was_unknown = true;
 	}
 
-	result = OpernameGetOprid(opname, arg1, arg2);
+	result = OpernameGetOprid(opname, arg1, arg2, false);
 	if (OidIsValid(result))
 		return result;
 
@@ -291,7 +291,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 
 		if (basetype != arg1)
 		{
-			result = OpernameGetOprid(opname, basetype, basetype);
+			result = OpernameGetOprid(opname, basetype, basetype, false);
 			if (OidIsValid(result))
 				return result;
 		}
@@ -544,7 +544,7 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
+	operOid = OpernameGetOprid(op, arg, InvalidOid, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
@@ -622,7 +622,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, InvalidOid, arg);
+	operOid = OpernameGetOprid(op, InvalidOid, arg, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ee6802a..c72fc8d 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -56,7 +56,8 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p)
+			   int32 *typmod_p,
+					bool missing_ok)
 {
 	Oid			typoid;
 	HeapTuple	tup;
@@ -116,15 +117,21 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 		 * concurrent DDL.	But taking a lock would carry a performance
 		 * penalty and would also require a permissions check.
 		 */
-		relid = RangeVarGetRelid(rel, NoLock, false);
-		attnum = get_attnum(relid, field);
-		if (attnum == InvalidAttrNumber)
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_COLUMN),
-					 errmsg("column \"%s\" of relation \"%s\" does not exist",
-							field, rel->relname),
-					 parser_errposition(pstate, typeName->location)));
-		typoid = get_atttype(relid, attnum);
+		typoid = InvalidOid;
+		relid = RangeVarGetRelid(rel, NoLock, missing_ok);
+
+		if (OidIsValid(relid))
+		{
+			attnum = get_attnum(relid, field);
+			if (attnum != InvalidAttrNumber)
+				typoid = get_atttype(relid, attnum);
+			else if (!missing_ok)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_COLUMN),
+						 errmsg("column \"%s\" of relation \"%s\" does not exist",
+								field, rel->relname),
+						 parser_errposition(pstate, typeName->location)));
+		}
 
 		/* this construct should never have an array indicator */
 		Assert(typeName->arrayBounds == NIL);
@@ -149,10 +156,13 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			/* Look in specific schema only */
 			Oid			namespaceId;
 
-			namespaceId = LookupExplicitNamespace(schemaname, false);
-			typoid = GetSysCacheOid2(TYPENAMENSP,
+			namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+			if (OidIsValid(namespaceId))
+				typoid = GetSysCacheOid2(TYPENAMENSP,
 									 PointerGetDatum(typname),
 									 ObjectIdGetDatum(namespaceId));
+			else
+				typoid = InvalidOid;
 		}
 		else
 		{
@@ -196,7 +206,7 @@ typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typeName, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -232,6 +242,35 @@ typenameTypeId(ParseState *pstate, const TypeName *typeName)
 }
 
 /*
+ * returns oid of type
+ *		Convenience routine to look up a type, silently accepting shell types
+ */
+Oid
+LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
+{
+	Oid			typoid;
+	Type		tup;
+
+	tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
+	if (tup == NULL)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typeName)),
+					 parser_errposition(pstate, typeName->location)));
+
+		return InvalidOid;
+	}
+
+	typoid = HeapTupleGetOid(tup);
+	ReleaseSysCache(tup);
+
+	return typoid;
+}
+
+/*
  * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
  *
  * This is equivalent to typenameType, but we only hand back the type OID
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index c24a2c1..28c1e7f 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -135,7 +135,7 @@ regprocin(PG_FUNCTION_ARGS)
 	 * pg_proc entries in the current search path.
 	 */
 	names = stringToQualifiedNameList(pro_name_or_oid);
-	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
+	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
 
 	if (clist == NULL)
 		ereport(ERROR,
@@ -192,7 +192,7 @@ regprocout(PG_FUNCTION_ARGS)
 			 * qualify it.
 			 */
 			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-										  -1, NIL, false, false);
+										  -1, NIL, false, false, false);
 			if (clist != NULL && clist->next == NULL &&
 				clist->oid == proid)
 				nspname = NULL;
@@ -279,7 +279,7 @@ regprocedurein(PG_FUNCTION_ARGS)
 	 */
 	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
 
-	clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
 
 	for (; clist; clist = clist->next)
 	{
@@ -661,7 +661,7 @@ regoperatorin(PG_FUNCTION_ARGS)
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
 
-	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
+	result = OpernameGetOprid(names, argtypes[0], argtypes[1], false);
 
 	if (!OidIsValid(result))
 		ereport(ERROR,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 4fadc74..05c035b 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -71,10 +71,11 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names,
 					  int nargs, List *argnames,
 					  bool expand_variadic,
-					  bool expand_defaults);
+					  bool expand_defaults,
+					  bool noError);
 extern bool FunctionIsVisible(Oid funcid);
 
-extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
+extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 340121a..51da025 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,7 +20,9 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p);
+			   int32 *typmod_p, bool missing_ok);
+extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
+				 bool missing_ok);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
 extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 426aeb5..692bba4 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1665,7 +1665,7 @@ plpgsql_parse_wordtype(char *ident)
 	 * Word wasn't found in the namespace stack. Try to find a data type with
 	 * that name, but ignore shell types and complex types.
 	 */
-	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, false);
 	if (typeTup)
 	{
 		Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 8599401..497ea6f 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -169,11 +169,15 @@ NOTICE:  cast from type text to type text does not exist, skipping
 DROP TRIGGER test_trigger_exists ON test_exists;
 ERROR:  trigger "test_trigger_exists" for table "test_exists" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
-NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, skipping
+NOTICE:  trigger "test_trigger_exists" for relation "test_exists" does not exist, skipping
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for relation "test_exists" does not exist, skip
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -223,3 +231,62 @@ ERROR:  access method "no_such_am" does not exist
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
 ERROR:  table "test_exists" does not exist
+-- be toleralnt with not existing schema or not existing type
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP AGGREGATE IF EXISTS foo(no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CAST IF EXISTS (no_such_type1 AS no_such_type2);
+NOTICE:  type "no_such_type1" does not exist, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS foo(no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS + (no_such_type, no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 656d47f..d4723b2 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -280,7 +280,7 @@ SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
 (23 rows)
 
 DROP OWNED BY regression_bob;
-NOTICE:  table "audit_tbls_schema_one_table_two" does not exist, skipping
+NOTICE:  schema "audit_tbls" does not exist, skipping
 CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index 6330566..94a9bcc 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON test_exists;
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -226,3 +232,35 @@ DROP OPERATOR FAMILY IF EXISTS test_operator_family USING no_such_am;
 DROP TABLE IF EXISTS test_exists;
 
 DROP TABLE test_exists;
+
+-- be toleralnt with not existing schema or not existing type
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP AGGREGATE IF EXISTS foo(no_such_type);
+DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type);
+DROP CAST IF EXISTS (no_such_type1 AS no_such_type2);
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+DROP COLLATION IF EXISTS no_such_schema.foo;
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+DROP FUNCTION IF EXISTS foo(no_such_type);
+DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type);
+DROP INDEX IF EXISTS no_such_schema.foo;
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+DROP OPERATOR IF EXISTS + (no_such_type, no_such_type);
+DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type);
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+DROP TABLE IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+DROP TYPE IF EXISTS no_such_schema.foo;
+DROP VIEW IF EXISTS no_such_schema.foo;
#78Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Pavel Stehule (#77)
1 attachment(s)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 7 December 2013 21:34, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Well I was basically proposing that does_not_exist_skipping() be
enhanced to report on non-existent types that form part of the object
specification. I think this would affect the CAST, FUNCTION, AGGREGATE
and OPERATOR cases, but should be a fairly trivial extension to the
code that you've already added.

ok, updated patch is in attachment

Cool. This looks good to me, except I found a corner case --- the type
name for an operator may be "NONE", in which case the typeName in the
list will be NULL, so that needs to be guarded against. Updated patch
attached.

I think this is a good patch. It makes all the DROP...IF EXISTS
commands consistently fault-tolerant, instead of the current 50/50
mix, and all the resulting NOTICEs give useful information about why
objects don't exist and are being skipped.

I think this is now ready for committer.

Nice work!

Regards,
Dean

Attachments:

drop-if-exists-consistency-v4.patchtext/x-diff; charset=US-ASCII; name=drop-if-exists-consistency-v4.patchDownload
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
new file mode 100644
index 4434dd6..b32f2e4
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -909,7 +909,7 @@ TypeIsVisible(Oid typid)
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-					  bool expand_variadic, bool expand_defaults)
+					  bool expand_variadic, bool expand_defaults, bool noError)
 {
 	FuncCandidateList resultList = NULL;
 	bool		any_special = false;
@@ -928,7 +928,9 @@ FuncnameGetCandidates(List *names, int n
 	if (schemaname)
 	{
 		/* use exact schema given */
-		namespaceId = LookupExplicitNamespace(schemaname, false);
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (!OidIsValid(namespaceId))
+			return NULL;
 	}
 	else
 	{
@@ -1414,7 +1416,7 @@ FunctionIsVisible(Oid funcid)
 		visible = false;
 
 		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-									  nargs, NIL, false, false);
+									  nargs, NIL, false, false, false);
 
 		for (; clist; clist = clist->next)
 		{
@@ -1446,7 +1448,7 @@ FunctionIsVisible(Oid funcid)
  * namespace search path.
  */
 Oid
-OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError)
 {
 	char	   *schemaname;
 	char	   *opername;
@@ -1462,18 +1464,21 @@ OpernameGetOprid(List *names, Oid oprlef
 		Oid			namespaceId;
 		HeapTuple	opertup;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		opertup = SearchSysCache4(OPERNAMENSP,
-								  CStringGetDatum(opername),
-								  ObjectIdGetDatum(oprleft),
-								  ObjectIdGetDatum(oprright),
-								  ObjectIdGetDatum(namespaceId));
-		if (HeapTupleIsValid(opertup))
+		namespaceId = LookupExplicitNamespace(schemaname, noError);
+		if (OidIsValid(namespaceId))
 		{
-			Oid			result = HeapTupleGetOid(opertup);
+			opertup = SearchSysCache4(OPERNAMENSP,
+									  CStringGetDatum(opername),
+									  ObjectIdGetDatum(oprleft),
+									  ObjectIdGetDatum(oprright),
+									  ObjectIdGetDatum(namespaceId));
+			if (HeapTupleIsValid(opertup))
+			{
+				Oid			result = HeapTupleGetOid(opertup);
 
-			ReleaseSysCache(opertup);
-			return result;
+				ReleaseSysCache(opertup);
+				return result;
+			}
 		}
 		return InvalidOid;
 	}
@@ -1734,7 +1739,8 @@ OperatorIsVisible(Oid oprid)
 		char	   *oprname = NameStr(oprform->oprname);
 
 		visible = (OpernameGetOprid(list_make1(makeString(oprname)),
-									oprform->oprleft, oprform->oprright)
+									oprform->oprleft, oprform->oprright,
+											   false)
 				   == oprid);
 	}
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
new file mode 100644
index 9011190..6a851fa
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -580,8 +580,8 @@ get_object_address(ObjectType objtype, L
 				{
 					TypeName   *sourcetype = (TypeName *) linitial(objname);
 					TypeName   *targettype = (TypeName *) linitial(objargs);
-					Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
-					Oid			targettypeid = typenameTypeId(NULL, targettype);
+					Oid	 sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+					Oid	 targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
 
 					address.classId = CastRelationId;
 					address.objectId =
@@ -942,26 +942,30 @@ get_object_address_relobject(ObjectType
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+							   AccessShareLock,
+							   missing_ok);
+
+		reloid = (relation != NULL) ? RelationGetRelid(relation) : InvalidOid;
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
+				address.objectId = OidIsValid(reloid) ?
+					get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
 			default:
@@ -975,7 +979,9 @@ get_object_address_relobject(ObjectType
 		/* Avoid relcache leak when object not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			heap_close(relation, AccessShareLock);
+			if (relation != NULL)
+				heap_close(relation, AccessShareLock);
+
 			relation = NULL;	/* department of accident prevention */
 			return address;
 		}
@@ -1052,7 +1058,7 @@ get_object_address_type(ObjectType objty
 	address.objectId = InvalidOid;
 	address.objectSubId = 0;
 
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, missing_ok);
 	if (!HeapTupleIsValid(tup))
 	{
 		if (!missing_ok)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
new file mode 100644
index b32ad3a..53f52f4
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -32,6 +32,17 @@
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
 
+static bool parent_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name);
+
+static bool schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name);
+static bool type_in_list_does_not_exist_skipping(List *typenames,
+							   const char **msg,
+							   char **name);
+
 /*
  * Drop one or more objects.
  *
@@ -125,6 +136,102 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * For triggers and rules, test if the parent relation exists.  If it does not,
+ * report it as missing rather than reporting the trigger or rule as missing.
+ * This is used for DROP RULE/TRIGGER IF EXISTS.
+ */
+static bool
+parent_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	List	   *parent_objname;
+	RangeVar   *parent_rel;
+
+	parent_objname = list_truncate(list_copy(objname),
+								   list_length(objname) - 1);
+
+	if (schema_does_not_exist_skipping(parent_objname, msg, name))
+		return true;
+
+	parent_rel = makeRangeVarFromNameList(parent_objname);
+
+	if (!OidIsValid(RangeVarGetRelid(parent_rel, NoLock, true)))
+	{
+		*msg = gettext_noop("relation \"%s\" does not exist, skipping");
+		*name = NameListToString(parent_objname);
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * If a schema was explicitly specified, test if it exists.  If it does not,
+ * report the schema as missing rather than the child object.
+ */
+static bool
+schema_does_not_exist_skipping(List *objname,
+							   const char **msg,
+							   char **name)
+{
+	RangeVar	*rel;
+
+	rel = makeRangeVarFromNameList(objname);
+
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		*msg = gettext_noop("schema \"%s\" does not exist, skipping");
+		*name = rel->schemaname;
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * For functions, casts, aggregates and operators check used datatypes.
+ * report a type as missing instead a master object.
+ *
+ * First parameter is a list of TypeNames.
+ */
+static bool
+type_in_list_does_not_exist_skipping(List *typenames,
+							   const char **msg,
+							   char **name)
+{
+	ListCell   *l;
+
+	foreach(l, typenames)
+	{
+		TypeName *typeName = (TypeName *) lfirst(l);
+
+		if (typeName != NULL)
+		{
+			Assert(IsA(typeName, TypeName));
+
+			if  (!OidIsValid(LookupTypeNameOid(NULL, typeName, true)))
+			{
+				/* type doesn't exist, try to find why */
+				if (schema_does_not_exist_skipping(typeName->names,
+												   msg, name))
+					return true;
+
+				*msg = gettext_noop("type \"%s\" does not exist, skipping");
+				*name = TypeNameToString(typeName);
+
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+/*
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
  * get_object_address() will throw an ERROR.
@@ -140,81 +247,124 @@ does_not_exist_skipping(ObjectType objty
 	{
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			msg = gettext_noop("type \"%s\" does not exist, skipping");
-			name = TypeNameToString(makeTypeNameFromNameList(objname));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("type \"%s\" does not exist, skipping");
+				name = TypeNameToString(makeTypeNameFromNameList(objname));
+			}
 			break;
 		case OBJECT_COLLATION:
-			msg = gettext_noop("collation \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("collation \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_CONVERSION:
-			msg = gettext_noop("conversion \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_SCHEMA:
 			msg = gettext_noop("schema \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_TSPARSER:
-			msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSDICTIONARY:
-			msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSTEMPLATE:
-			msg = gettext_noop("text search template \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_TSCONFIGURATION:
-			msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_EXTENSION:
 			msg = gettext_noop("extension \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_FUNCTION:
-			msg = gettext_noop("function %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name)
+				   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+			{
+				msg = gettext_noop("function %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_AGGREGATE:
-			msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
-			name = NameListToString(objname);
-			args = TypeNameListToString(objargs);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name)
+				   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+			{
+				msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
+				name = NameListToString(objname);
+				args = TypeNameListToString(objargs);
+			}
 			break;
 		case OBJECT_OPERATOR:
-			msg = gettext_noop("operator %s does not exist, skipping");
-			name = NameListToString(objname);
+			if (!schema_does_not_exist_skipping(objname, &msg, &name)
+				   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+			{
+				msg = gettext_noop("operator %s does not exist, skipping");
+				name = NameListToString(objname);
+			}
 			break;
 		case OBJECT_LANGUAGE:
 			msg = gettext_noop("language \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_CAST:
-			msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
-			name = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objname)));
-			args = format_type_be(typenameTypeId(NULL,
-											(TypeName *) linitial(objargs)));
+			{
+				if (!type_in_list_does_not_exist_skipping(objname, &msg, &name)
+					   && !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+				{
+					msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+					name = TypeNameToString((TypeName *) linitial(objname));
+					args = TypeNameToString((TypeName *) linitial(objargs));
+				}
+			}
 			break;
 		case OBJECT_TRIGGER:
-			msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			if (!parent_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
+				name = strVal(llast(objname));
+				args = NameListToString(list_truncate(list_copy(objname),
+													  list_length(objname) - 1));
+			}
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
 			name = NameListToString(objname);
 			break;
 		case OBJECT_RULE:
-			msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-			name = strVal(llast(objname));
-			args = NameListToString(list_truncate(list_copy(objname),
-												  list_length(objname) - 1));
+			if (!parent_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
+				name = strVal(llast(objname));
+				args = NameListToString(list_truncate(list_copy(objname),
+													  list_length(objname) - 1));
+			}
 			break;
 		case OBJECT_FDW:
 			msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
@@ -225,14 +375,20 @@ does_not_exist_skipping(ObjectType objty
 			name = NameListToString(objname);
 			break;
 		case OBJECT_OPCLASS:
-			msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		case OBJECT_OPFAMILY:
-			msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
-			name = NameListToString(objname);
-			args = strVal(linitial(objargs));
+			if (!schema_does_not_exist_skipping(objname, &msg, &name))
+			{
+				msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
+				name = NameListToString(objname);
+				args = strVal(linitial(objargs));
+			}
 			break;
 		default:
 			elog(ERROR, "unexpected object type (%d)", (int) objtype);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
new file mode 100644
index ca754b4..348b901
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -86,7 +86,7 @@ compute_return_type(TypeName *returnType
 	Type		typtup;
 	AclResult	aclresult;
 
-	typtup = LookupTypeName(NULL, returnType, NULL);
+	typtup = LookupTypeName(NULL, returnType, NULL, false);
 
 	if (typtup)
 	{
@@ -220,7 +220,7 @@ interpret_function_parameter_list(List *
 		Type		typtup;
 		AclResult	aclresult;
 
-		typtup = LookupTypeName(NULL, t, NULL);
+		typtup = LookupTypeName(NULL, t, NULL, false);
 		if (typtup)
 		{
 			if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644
index 3140b37..576f7b1
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -103,11 +103,14 @@ OpFamilyCacheLookup(Oid amID, List *opfa
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(OPFAMILYAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opfname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(OPFAMILYAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opfname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
@@ -179,11 +182,14 @@ OpClassCacheLookup(Oid amID, List *opcla
 		/* Look in specific schema only */
 		Oid			namespaceId;
 
-		namespaceId = LookupExplicitNamespace(schemaname, false);
-		htup = SearchSysCache3(CLAAMNAMENSP,
-							   ObjectIdGetDatum(amID),
-							   PointerGetDatum(opcname),
-							   ObjectIdGetDatum(namespaceId));
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			htup = NULL;
+		else
+			htup = SearchSysCache3(CLAAMNAMENSP,
+								   ObjectIdGetDatum(amID),
+								   PointerGetDatum(opcname),
+								   ObjectIdGetDatum(namespaceId));
 	}
 	else
 	{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 1d9f29a..2a7ab51
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -690,10 +690,28 @@ DefineRelation(CreateStmt *stmt, char re
  * non-existent relation
  */
 static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
 {
 	const struct dropmsgstrings *rentry;
 
+	if (rel->schemaname != NULL &&
+		!OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+	{
+		if (!missing_ok)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_SCHEMA),
+					 errmsg("schema \"%s\" does not exist", rel->schemaname)));
+		}
+		else
+		{
+			ereport(NOTICE,
+					(errmsg("schema \"%s\" does not exist, skipping",
+							rel->schemaname)));
+		}
+		return;
+	}
+
 	for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
 	{
 		if (rentry->kind == rightkind)
@@ -702,11 +720,11 @@ DropErrorMsgNonExistent(const char *reln
 			{
 				ereport(ERROR,
 						(errcode(rentry->nonexistent_code),
-						 errmsg(rentry->nonexistent_msg, relname)));
+						 errmsg(rentry->nonexistent_msg, rel->relname)));
 			}
 			else
 			{
-				ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
+				ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
 				break;
 			}
 		}
@@ -845,7 +863,7 @@ RemoveRelations(DropStmt *drop)
 		/* Not there? */
 		if (!OidIsValid(relOid))
 		{
-			DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+			DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
 			continue;
 		}
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
new file mode 100644
index d4a14ca..4805f2b
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3245,7 +3245,7 @@ AlterTypeOwner(List *names, Oid newOwner
 	typename = makeTypeNameFromNameList(names);
 
 	/* Use LookupTypeName here so that shell types can be processed */
-	tup = LookupTypeName(NULL, typename, NULL);
+	tup = LookupTypeName(NULL, typename, NULL, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
new file mode 100644
index ede36d1..f560b48
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1062,7 +1062,8 @@ func_get_detail(List *funcname,
 
 	/* Get list of possible candidates from namespace search */
 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
-										   expand_variadic, expand_defaults);
+										   expand_variadic, expand_defaults,
+													   false);
 
 	/*
 	 * Quickly check if there is an exact match to the input datatypes (there
@@ -1422,7 +1423,7 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
-	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+	typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
 	if (typtup == NULL)
 		return InvalidOid;
 
@@ -1581,7 +1582,7 @@ LookupFuncName(List *funcname, int nargs
 {
 	FuncCandidateList clist;
 
-	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
 
 	while (clist)
 	{
@@ -1601,27 +1602,6 @@ LookupFuncName(List *funcname, int nargs
 }
 
 /*
- * LookupTypeNameOid
- *		Convenience routine to look up a type, silently accepting shell types
- */
-static Oid
-LookupTypeNameOid(const TypeName *typename)
-{
-	Oid			result;
-	Type		typtup;
-
-	typtup = LookupTypeName(NULL, typename, NULL);
-	if (typtup == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename))));
-	result = typeTypeId(typtup);
-	ReleaseSysCache(typtup);
-	return result;
-}
-
-/*
  * LookupFuncNameTypeNames
  *		Like LookupFuncName, but the argument types are specified by a
  *		list of TypeName nodes.
@@ -1648,7 +1628,7 @@ LookupFuncNameTypeNames(List *funcname,
 	{
 		TypeName   *t = (TypeName *) lfirst(args_item);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		args_item = lnext(args_item);
 	}
 
@@ -1688,7 +1668,7 @@ LookupAggNameTypeNames(List *aggname, Li
 	{
 		TypeName   *t = (TypeName *) lfirst(lc);
 
-		argoids[i] = LookupTypeNameOid(t);
+		argoids[i] = LookupTypeNameOid(NULL, t, noError);
 		i++;
 	}
 
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
new file mode 100644
index dd80fa9..9595f10
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -103,7 +103,7 @@ LookupOperName(ParseState *pstate, List
 {
 	Oid			result;
 
-	result = OpernameGetOprid(opername, oprleft, oprright);
+	result = OpernameGetOprid(opername, oprleft, oprright, noError);
 	if (OidIsValid(result))
 		return result;
 
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *psta
 	if (oprleft == NULL)
 		leftoid = InvalidOid;
 	else
-		leftoid = typenameTypeId(pstate, oprleft);
+		leftoid = LookupTypeNameOid(pstate, oprleft, noError);
 
 	if (oprright == NULL)
 		rightoid = InvalidOid;
 	else
-		rightoid = typenameTypeId(pstate, oprright);
+		rightoid = LookupTypeNameOid(pstate, oprright, noError);
 
 	return LookupOperName(pstate, opername, leftoid, rightoid,
 						  noError, location);
@@ -280,7 +280,7 @@ binary_oper_exact(List *opname, Oid arg1
 		was_unknown = true;
 	}
 
-	result = OpernameGetOprid(opname, arg1, arg2);
+	result = OpernameGetOprid(opname, arg1, arg2, false);
 	if (OidIsValid(result))
 		return result;
 
@@ -291,7 +291,7 @@ binary_oper_exact(List *opname, Oid arg1
 
 		if (basetype != arg1)
 		{
-			result = OpernameGetOprid(opname, basetype, basetype);
+			result = OpernameGetOprid(opname, basetype, basetype, false);
 			if (OidIsValid(result))
 				return result;
 		}
@@ -544,7 +544,7 @@ right_oper(ParseState *pstate, List *op,
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
+	operOid = OpernameGetOprid(op, arg, InvalidOid, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
@@ -622,7 +622,7 @@ left_oper(ParseState *pstate, List *op,
 	/*
 	 * First try for an "exact" match.
 	 */
-	operOid = OpernameGetOprid(op, InvalidOid, arg);
+	operOid = OpernameGetOprid(op, InvalidOid, arg, noError);
 	if (!OidIsValid(operOid))
 	{
 		/*
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
new file mode 100644
index ee6802a..c72fc8d
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -56,7 +56,8 @@ static int32 typenameTypeMod(ParseState
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p)
+			   int32 *typmod_p,
+					bool missing_ok)
 {
 	Oid			typoid;
 	HeapTuple	tup;
@@ -116,15 +117,21 @@ LookupTypeName(ParseState *pstate, const
 		 * concurrent DDL.	But taking a lock would carry a performance
 		 * penalty and would also require a permissions check.
 		 */
-		relid = RangeVarGetRelid(rel, NoLock, false);
-		attnum = get_attnum(relid, field);
-		if (attnum == InvalidAttrNumber)
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_COLUMN),
-					 errmsg("column \"%s\" of relation \"%s\" does not exist",
-							field, rel->relname),
-					 parser_errposition(pstate, typeName->location)));
-		typoid = get_atttype(relid, attnum);
+		typoid = InvalidOid;
+		relid = RangeVarGetRelid(rel, NoLock, missing_ok);
+
+		if (OidIsValid(relid))
+		{
+			attnum = get_attnum(relid, field);
+			if (attnum != InvalidAttrNumber)
+				typoid = get_atttype(relid, attnum);
+			else if (!missing_ok)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_COLUMN),
+						 errmsg("column \"%s\" of relation \"%s\" does not exist",
+								field, rel->relname),
+						 parser_errposition(pstate, typeName->location)));
+		}
 
 		/* this construct should never have an array indicator */
 		Assert(typeName->arrayBounds == NIL);
@@ -149,10 +156,13 @@ LookupTypeName(ParseState *pstate, const
 			/* Look in specific schema only */
 			Oid			namespaceId;
 
-			namespaceId = LookupExplicitNamespace(schemaname, false);
-			typoid = GetSysCacheOid2(TYPENAMENSP,
+			namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+			if (OidIsValid(namespaceId))
+				typoid = GetSysCacheOid2(TYPENAMENSP,
 									 PointerGetDatum(typname),
 									 ObjectIdGetDatum(namespaceId));
+			else
+				typoid = InvalidOid;
 		}
 		else
 		{
@@ -196,7 +206,7 @@ typenameType(ParseState *pstate, const T
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typeName, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p, false);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -228,6 +238,35 @@ typenameTypeId(ParseState *pstate, const
 	typoid = HeapTupleGetOid(tup);
 	ReleaseSysCache(tup);
 
+	return typoid;
+}
+
+/*
+ * returns oid of type
+ *		Convenience routine to look up a type, silently accepting shell types
+ */
+Oid
+LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
+{
+	Oid			typoid;
+	Type		tup;
+
+	tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
+	if (tup == NULL)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typeName)),
+					 parser_errposition(pstate, typeName->location)));
+
+		return InvalidOid;
+	}
+
+	typoid = HeapTupleGetOid(tup);
+	ReleaseSysCache(tup);
+
 	return typoid;
 }
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
new file mode 100644
index c24a2c1..28c1e7f
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -135,7 +135,7 @@ regprocin(PG_FUNCTION_ARGS)
 	 * pg_proc entries in the current search path.
 	 */
 	names = stringToQualifiedNameList(pro_name_or_oid);
-	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
+	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
 
 	if (clist == NULL)
 		ereport(ERROR,
@@ -192,7 +192,7 @@ regprocout(PG_FUNCTION_ARGS)
 			 * qualify it.
 			 */
 			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-										  -1, NIL, false, false);
+										  -1, NIL, false, false, false);
 			if (clist != NULL && clist->next == NULL &&
 				clist->oid == proid)
 				nspname = NULL;
@@ -279,7 +279,7 @@ regprocedurein(PG_FUNCTION_ARGS)
 	 */
 	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
 
-	clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
+	clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
 
 	for (; clist; clist = clist->next)
 	{
@@ -661,7 +661,7 @@ regoperatorin(PG_FUNCTION_ARGS)
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
 
-	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
+	result = OpernameGetOprid(names, argtypes[0], argtypes[1], false);
 
 	if (!OidIsValid(result))
 		ereport(ERROR,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
new file mode 100644
index 4fadc74..05c035b
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -71,10 +71,11 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names,
 					  int nargs, List *argnames,
 					  bool expand_variadic,
-					  bool expand_defaults);
+					  bool expand_defaults,
+					  bool noError);
 extern bool FunctionIsVisible(Oid funcid);
 
-extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
+extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
new file mode 100644
index 340121a..51da025
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,7 +20,9 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-			   int32 *typmod_p);
+			   int32 *typmod_p, bool missing_ok);
+extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
+				 bool missing_ok);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
 extern Oid	typenameTypeId(ParseState *pstate, const TypeName *typeName);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
new file mode 100644
index 426aeb5..692bba4
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1665,7 +1665,7 @@ plpgsql_parse_wordtype(char *ident)
 	 * Word wasn't found in the namespace stack. Try to find a data type with
 	 * that name, but ignore shell types and complex types.
 	 */
-	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+	typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, false);
 	if (typeTup)
 	{
 		Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
new file mode 100644
index 8599401..a7cd62a
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -169,11 +169,15 @@ NOTICE:  cast from type text to type tex
 DROP TRIGGER test_trigger_exists ON test_exists;
 ERROR:  trigger "test_trigger_exists" for table "test_exists" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
-NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, skipping
+NOTICE:  trigger "test_trigger_exists" for relation "test_exists" does not exist, skipping
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for rel
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -223,3 +231,64 @@ ERROR:  access method "no_such_am" does
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
 ERROR:  table "test_exists" does not exist
+-- be toleralnt with not existing schema or not existing type
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP AGGREGATE IF EXISTS foo(no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CAST IF EXISTS (no_such_type1 AS no_such_type2);
+NOTICE:  type "no_such_type1" does not exist, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS foo(no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS + (no_such_type, no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS # (NONE, no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
new file mode 100644
index 656d47f..d4723b2
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -280,7 +280,7 @@ SELECT * FROM dropped_objects WHERE sche
 (23 rows)
 
 DROP OWNED BY regression_bob;
-NOTICE:  table "audit_tbls_schema_one_table_two" does not exist, skipping
+NOTICE:  schema "audit_tbls" does not exist, skipping
 CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
new file mode 100644
index 6330566..efb3a4a
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exis
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -226,3 +232,36 @@ DROP OPERATOR FAMILY IF EXISTS test_oper
 DROP TABLE IF EXISTS test_exists;
 
 DROP TABLE test_exists;
+
+-- be toleralnt with not existing schema or not existing type
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP AGGREGATE IF EXISTS foo(no_such_type);
+DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type);
+DROP CAST IF EXISTS (no_such_type1 AS no_such_type2);
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+DROP COLLATION IF EXISTS no_such_schema.foo;
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+DROP FUNCTION IF EXISTS foo(no_such_type);
+DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type);
+DROP INDEX IF EXISTS no_such_schema.foo;
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+DROP OPERATOR IF EXISTS + (no_such_type, no_such_type);
+DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type);
+DROP OPERATOR IF EXISTS # (NONE, no_such_schema.no_such_type);
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+DROP TABLE IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+DROP TYPE IF EXISTS no_such_schema.foo;
+DROP VIEW IF EXISTS no_such_schema.foo;
#79Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#78)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

2013/12/8 Dean Rasheed <dean.a.rasheed@gmail.com>

On 7 December 2013 21:34, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Well I was basically proposing that does_not_exist_skipping() be
enhanced to report on non-existent types that form part of the object
specification. I think this would affect the CAST, FUNCTION, AGGREGATE
and OPERATOR cases, but should be a fairly trivial extension to the
code that you've already added.

ok, updated patch is in attachment

Cool. This looks good to me, except I found a corner case --- the type
name for an operator may be "NONE", in which case the typeName in the
list will be NULL, so that needs to be guarded against. Updated patch
attached.

I think this is a good patch. It makes all the DROP...IF EXISTS
commands consistently fault-tolerant, instead of the current 50/50
mix, and all the resulting NOTICEs give useful information about why
objects don't exist and are being skipped.

I think this is now ready for committer.

thank you :)

Pavel

Show quoted text

Nice work!

Regards,
Dean

#80Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Dean Rasheed (#78)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

I have been mulling over this patch, and I can't seem to come to terms
with it. I first started making it look nicer here and there, thinking
it was all mostly okay, but eventually arrived at the idea that it seems
wrong to do what this does: basically, get_object_address() tries to
obtain an object address, and if that fails, return InvalidOid; then, in
RemoveObjects, we try rather hard to figure out why that failed, and
construct an error message.

It seems to me that it would make more sense to have get_object_address
somehow return a code indicating what failed; then we don't have to go
all over through the parser code once more. Perhaps, for example, when
missing_ok is given as true to get_object_address it also needs to get a
pointer to ObjectType and a string; if some object does not exist then
fill the ObjectType with the failing object and the string with the
failing name. Then RemoveObjects can construct a string more easily.
Not sure how workable this exact idea is; maybe there is a better way.

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#81Dean Rasheed
dean.a.rasheed@gmail.com
In reply to: Alvaro Herrera (#80)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

On 21 January 2014 22:28, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

I have been mulling over this patch, and I can't seem to come to terms
with it. I first started making it look nicer here and there, thinking
it was all mostly okay, but eventually arrived at the idea that it seems
wrong to do what this does: basically, get_object_address() tries to
obtain an object address, and if that fails, return InvalidOid; then, in
RemoveObjects, we try rather hard to figure out why that failed, and
construct an error message.

It seems to me that it would make more sense to have get_object_address
somehow return a code indicating what failed; then we don't have to go
all over through the parser code once more. Perhaps, for example, when
missing_ok is given as true to get_object_address it also needs to get a
pointer to ObjectType and a string; if some object does not exist then
fill the ObjectType with the failing object and the string with the
failing name. Then RemoveObjects can construct a string more easily.
Not sure how workable this exact idea is; maybe there is a better way.

Yeah, when I initially started reviewing this patch I had a very
similar thought. But when I looked more deeply at the code beneath
get_object_address, I started to doubt whether it could be done
without rather extensive changes all over the place. Also
get_object_address is itself called from a lot of places (not
necessarily all in our code) and all the other places (in our code, at
least) pass missing_ok=false. So it seemed rather ugly to change its
signature and force a matching change in all those other places, which
actually don't care about missing objects. Perhaps the answer would be
to have a separate get_object_address_if_exists function, and remove
the missing_ok flag from get_object_address, but that all felt like a
much larger patch.

In the end, I felt that Pavel's approach wasn't adding that much new
code, and it's all localised in the one place that does actually
tolerate missing objects.

I admit though, that I didn't explore the other approach very deeply,
so perhaps it might fall out more neatly than I feared.

Regards,
Dean

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#82Pavel Stehule
pavel.stehule@gmail.com
In reply to: Dean Rasheed (#81)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Hello

2014/1/22 Dean Rasheed <dean.a.rasheed@gmail.com>

On 21 January 2014 22:28, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

I have been mulling over this patch, and I can't seem to come to terms
with it. I first started making it look nicer here and there, thinking
it was all mostly okay, but eventually arrived at the idea that it seems
wrong to do what this does: basically, get_object_address() tries to
obtain an object address, and if that fails, return InvalidOid; then, in
RemoveObjects, we try rather hard to figure out why that failed, and
construct an error message.

It seems to me that it would make more sense to have get_object_address
somehow return a code indicating what failed; then we don't have to go
all over through the parser code once more. Perhaps, for example, when
missing_ok is given as true to get_object_address it also needs to get a
pointer to ObjectType and a string; if some object does not exist then
fill the ObjectType with the failing object and the string with the
failing name. Then RemoveObjects can construct a string more easily.
Not sure how workable this exact idea is; maybe there is a better way.

Yeah, when I initially started reviewing this patch I had a very
similar thought. But when I looked more deeply at the code beneath
get_object_address, I started to doubt whether it could be done
without rather extensive changes all over the place. Also
get_object_address is itself called from a lot of places (not
necessarily all in our code) and all the other places (in our code, at
least) pass missing_ok=false. So it seemed rather ugly to change its
signature and force a matching change in all those other places, which
actually don't care about missing objects. Perhaps the answer would be
to have a separate get_object_address_if_exists function, and remove
the missing_ok flag from get_object_address, but that all felt like a
much larger patch.

In the end, I felt that Pavel's approach wasn't adding that much new
code, and it's all localised in the one place that does actually
tolerate missing objects.

I though about it too. But I didn't continue - reasons was named by Dean -
and RemoveObjects are not difficult code - lot of code is mechanical - and
it is not on critical path.

Regards

Pavel

Show quoted text

I admit though, that I didn't explore the other approach very deeply,
so perhaps it might fall out more neatly than I feared.

Regards,
Dean

#83Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavel Stehule (#82)
Re: Re: [BUGS] BUG #7873: pg_restore --clean tries to drop tables that don't exist

Pavel Stehule escribi�:

I though about it too. But I didn't continue - reasons was named by Dean -
and RemoveObjects are not difficult code - lot of code is mechanical - and
it is not on critical path.

I have pushed it after some editorialization.

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers