Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

Started by Fabrízio de Royes Melloover 12 years ago60 messages
#1Fabrízio de Royes Mello
fabriziomello@gmail.com

Hi all,

I working in a patch to include support of "IF NOT EXISTS" into "CREATE"
statements that not have it yet.

I started with "DefineStmt" section from "src/backend/parser/gram.y":
- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]
- CREATE TEXT SEARCH {PARSER | DITIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...

My intention is cover anothers CREATE statements too, not just the above.

If has no objection about this implementation I'll finish him and soon I
sent the patch.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#2Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Fabrízio de Royes Mello (#1)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Fri, May 24, 2013 at 12:22 PM, Fabrízio de Royes Mello <
fabriziomello@gmail.com> wrote:

Hi all,

I working in a patch to include support of "IF NOT EXISTS" into "CREATE"
statements that not have it yet.

I started with "DefineStmt" section from "src/backend/parser/gram.y":
- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]
- CREATE TEXT SEARCH {PARSER | DITIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...

The attached patch add support to "IF NOT EXISTS" to "CREATE" statements
listed below:

- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE CAST [ IF NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TEXT SEARCH {PARSER | DICTIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

Attachments:

create_if_not_exists.patchapplication/octet-stream; name=create_if_not_exists.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..83a803b 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same 
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..86f8720 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+	  with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..2df11ab 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary 
+	  with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..177278c 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+	  with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..b60243e 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+	  the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 45a84e4..e13b450 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -964,7 +964,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1221,7 +1222,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e80b600..4452ba3 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -228,7 +229,7 @@ AggregateCreate(const char *aggName,
 
 	procOid = ProcedureCreate(aggName,
 							  aggNamespace,
-							  false,	/* no replacement */
+							  false,	/* replacement */
 							  false,	/* doesn't return a set */
 							  finaltype,		/* returnType */
 							  GetUserId(),		/* proowner */
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..7466e76 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool if_not_exists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -416,11 +417,18 @@ OperatorCreate(const char *operatorName,
 								   rightTypeId,
 								   &operatorAlreadyDefined);
 
-	if (operatorAlreadyDefined)
+	if (operatorAlreadyDefined && !if_not_exists)
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
 				 errmsg("operator %s already exists",
 						operatorName)));
+	if (operatorAlreadyDefined && if_not_exists) {
+		ereport(NOTICE,
+				(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				 errmsg("operator %s already exists, skipping",
+						operatorName)));
+		return InvalidOid;
+	}
 
 	/*
 	 * At this point, if operatorObjectId is not InvalidOid then we are
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..ef03cfd 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				errmsg("function \"%s\" already exists with same argument types",
+					   procedureName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..3d55360 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,20 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", typeName)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", typeName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 38187a8..490c7c8 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,26 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("cast from type %s to type %s already exists",
-						format_type_be(sourcetypeid),
-						format_type_be(targettypeid))));
+	{
+		if (!stmt->if_not_exists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 6e4c682..e107e1d 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 57b69f8..a993df2 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,30 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists",
+							get_namespace_name(namespaceoid),
+							prsname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +422,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +436,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+							dictnamespace,
+							dictname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +768,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +789,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1022,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1032,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1042,39 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists",
+							cfgnamespace,
+							cfgname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+	}
+
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 6bc16f1..325cbe8 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -113,7 +113,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -232,9 +232,19 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", typeName)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", typeName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -584,7 +594,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -620,11 +634,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -1010,7 +1025,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   false);		/* if not exists flag */
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1083,9 +1099,19 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", enumName)));
+		{
+			if (!stmt->if_not_exists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", enumName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1122,7 +1148,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1162,7 +1192,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1301,9 +1332,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", typeName)));
+		{
+			if (!stmt->if_not_exists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", typeName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/*
@@ -1456,7 +1497,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1497,7 +1542,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1568,7 +1614,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2017,7 +2064,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2053,9 +2100,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b5b8d63..7d71d7a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2763,6 +2763,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3022,6 +3023,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3033,6 +3035,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3044,6 +3047,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3658,6 +3662,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3f96595..75e0c44 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1117,6 +1117,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1338,6 +1339,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1347,6 +1349,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1356,6 +1359,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1874,6 +1878,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5094226..3c32bcb 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4594,6 +4594,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4605,6 +4617,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4615,6 +4640,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4625,6 +4662,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4636,6 +4685,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4645,6 +4707,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4652,6 +4725,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4659,6 +4741,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4668,6 +4759,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4677,6 +4779,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4686,6 +4799,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4695,6 +4819,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4704,6 +4839,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4713,6 +4859,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4814,8 +4971,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6683,37 +6840,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 01d165f..5847c35 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 6723647..6339538 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1870,6 +1870,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -2284,6 +2285,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2295,6 +2297,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2306,6 +2309,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2566,6 +2570,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 1d7e524..9095ddb 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -406,6 +406,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -430,6 +434,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 8656864..f59243e 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 04c5cc1..2ee71f9 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -334,6 +334,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -354,6 +356,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index dcad804..002474b 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,21 +26,17 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#3Peter Eisentraut
peter_e@gmx.net
In reply to: Fabrízio de Royes Mello (#2)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 6/12/13 1:29 PM, Fabr�zio de Royes Mello wrote:

The attached patch add support to "IF NOT EXISTS" to "CREATE" statements
listed below:

- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE CAST [ IF NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TEXT SEARCH {PARSER | DICTIONARY | TEMPLATE | CONFIGURATION} [
IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]

I'm wondering where "IF NOT EXISTS" and "OR REPLACE" will meet.

For example, why doesn't your list include CREATE FUNCTION?

I have on my personal todo list to add "OR REPLACE" support to CREATE
AGGREGATE and CREATE OPERATOR. They are kind of like functions, after
all, and CREATE OR REPLACE FUNCTION is clearly widely useful.

I suppose both could be useful, but if we're going to make sweeping
changes, perhaps that should be clarified.

Btw., I also want REPLACE BUT DO NOT CREATE.

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

#4Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Peter Eisentraut (#3)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Wed, Jun 12, 2013 at 4:00 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

I'm wondering where "IF NOT EXISTS" and "OR REPLACE" will meet.

For example, why doesn't your list include CREATE FUNCTION?

I have on my personal todo list to add "OR REPLACE" support to CREATE
AGGREGATE and CREATE OPERATOR. They are kind of like functions, after
all, and CREATE OR REPLACE FUNCTION is clearly widely useful.

I suppose both could be useful, but if we're going to make sweeping
changes, perhaps that should be clarified.

I did not include "CREATE FUNCTION" precisely because I had the same doubts.

IMO the "IF NOT EXISTS" and "OR REPLACE" are differents, and can coexists in
the same statements but not used at the same time:

CREATE [ OF REPLACE | IF NOT EXISTS ] FUNCTION ...

I can use "IF NOT EXISTS" to "CREATE" a {FUNCTION | AGGREGATE | OPERATOR}
without replace (OR REPLACE) its definition to just create missing objects
and don't
raise an exception if already exists.

Btw., I also want REPLACE BUT DO NOT CREATE.

Can you explain more about it?

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#5Tom Dunstan
pgsql@tomd.cc
In reply to: Peter Eisentraut (#3)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 13 June 2013 04:30, Peter Eisentraut <peter_e@gmx.net> wrote:

I'm wondering where "IF NOT EXISTS" and "OR REPLACE" will meet.

CREATE OR REPLACE (or ALTER / UPDATE ?) would definitely be useful for
enums, where it would be nice if we could teach an ORM to generate DDL
based on the current values of the enum in code, and know that after the
operation had completed, the database enum type matched the code enum type.
I don't think a sequence of ALTER TYPE ADD VALUE IF NOT EXISTS quite does
the trick, as it doesn't guarantee that the db enum is in the same order as
the code enum, which may or may not be important. I'd expect a CREATE OR
ALTER for enums to raise an error if any of the elements were out of order.

Currently to get to a known state for enums you have to write manual
migration scripts, and while that tends to be how I roll anyway, often when
starting projects in rails / grails / hibernate etc people rely on db
schemas generated by the framework as it lets them prototype with less
mucking around. It would be nice for those frameworks to be able to
generate enum types in a known state.

Cheers

Tom

#6Robins Tharakan
tharakan@gmail.com
In reply to: Fabrízio de Royes Mello (#1)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

Hi,

Did some basic checks on this patch. List-wise feedback below.

- Removed unnecessary extra-lines: Yes
- Cleanly applies to Git-Head: Yes
- Documentation Updated: Yes
- Tests Updated: Yes
- All tests pass: Yes. (But see Note below)
- Does it Work (CREATE AGGREGATE): Yes
- Does it Work (CREATE OPERATOR): Yes
- Does it Work (CREATE TYPE): Yes
- Does it Work (CREATE TEXT SEARCH): Yes
- Does it Work (CREATE COLLATION): Yes

- Do we want it?: ???

- Is this a new feature: Yes
- Does it support pg_dump: Unable to test currently :(
- Does it follow coding guidelines: Yes

- Any visible issues: No
- Any corner cases missed out: Some tests are not extensive (eg. CREATE
COLLATION).
- Performance tests required: No
- Any compiler warnings: A scan.c warning (scan.c:10181:23: warning: unused
variable ‘yyg’ [-Wunused-variable]) although I doubt that is being caused
by this patch.
- Are comments sufficient: Can't comment much on code comments.

- Others:
Number of new lines added not covered by tests: ~208

======
A typical kind of ERROR is emitted in most tests. (Verified at least in
CREATE AGGREGATE / OPERATOR / TEXT SEARCH TEMPLATE).

For e.g. CREATE OPERATOR IF NOT EXISTS tries to create an OPERATOR that is
already created in the test a few lines above. So although the feature is
tested, the test unnecessarily creates the first OPERATOR. If you need to
maintain 'completeness' within each tests, you could use unique numbering
of objects instead.

CREATE OPERATOR ## (
leftarg = path,
rightarg = path,
procedure = path_inter,
commutator = ##
);
CREATE OPERATOR ## (
leftarg = path,
rightarg = path,
procedure = path_inter,
commutator = ##
);
ERROR: operator ## already exists
CREATE OPERATOR IF NOT EXISTS ## (
leftarg = path,
rightarg = path,
procedure = path_inter,
commutator = ##
);
NOTICE: operator ## already exists, skipping

=====

--
Robins Tharakan

On 24 May 2013 20:52, Fabrízio de Royes Mello <fabriziomello@gmail.com>wrote:

Hi all,

I working in a patch to include support of "IF NOT EXISTS" into "CREATE"
statements that not have it yet.

I started with "DefineStmt" section from "src/backend/parser/gram.y":
- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]
- CREATE TEXT SEARCH {PARSER | DITIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...

My intention is cover anothers CREATE statements too, not just the above.

If has no objection about this implementation I'll finish him and soon I
sent the patch.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

On 24 May 2013 20:52, Fabrízio de Royes Mello <fabriziomello@gmail.com>wrote:

Hi all,

I working in a patch to include support of "IF NOT EXISTS" into "CREATE"
statements that not have it yet.

I started with "DefineStmt" section from "src/backend/parser/gram.y":
- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]
- CREATE TEXT SEARCH {PARSER | DITIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...

My intention is cover anothers CREATE statements too, not just the above.

If has no objection about this implementation I'll finish him and soon I
sent the patch.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#7Peter Eisentraut
peter_e@gmx.net
In reply to: Fabrízio de Royes Mello (#4)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Wed, 2013-06-12 at 16:31 -0300, Fabrízio de Royes Mello wrote:

Btw., I also want REPLACE BUT DO NOT CREATE.

Can you explain more about it?

Replace/alter the object if it already exists, but fail if it does not
exist.

The complete set of variants is:

- object does not exist:

- proceed (normal CREATE)
- error (my above description)

- object exists:

- replace (CREATE OR REPLACE)
- skip (CREATE IF NOT EXISTS)
- error (normal CREATE)

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

#8Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Robins Tharakan (#6)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Mon, Jun 17, 2013 at 12:36 AM, Robins Tharakan <tharakan@gmail.com>wrote:

Hi,

Did some basic checks on this patch. List-wise feedback below.

[...]

Dear Robins,

Thanks for your review. I attach your considerations to Commit Fest [1]https://commitfest.postgresql.org/action/patch_view?id=1133.

Regards,

[1]: https://commitfest.postgresql.org/action/patch_view?id=1133

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#9Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Peter Eisentraut (#7)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Mon, Jun 17, 2013 at 11:33 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

Replace/alter the object if it already exists, but fail if it does not
exist.

The complete set of variants is:

- object does not exist:

- proceed (normal CREATE)
- error (my above description)

- object exists:

- replace (CREATE OR REPLACE)
- skip (CREATE IF NOT EXISTS)
- error (normal CREATE)

I understood.

The syntax can be like that?
- CREATE [ OR REPLACE | IF NOT EXISTS ] AGGREGATE ...
- CREATE [ OR REPLACE | IF NOT EXISTS ] OPERATOR ...
- CREATE [ OR REPLACE | IF NOT EXISTS ] FUNCTION ...

I can add this features too, but IMHO it is more prudent at this CF we just
implement the IF NOT EXISTS according the initial proposal.

I'm planning another patch do next CF to add support to "IF NOT EXISTS" to
others "CREATE" statements. See my planning [1]https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing.

Regards,

[1]: https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing
https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#10Amit Langote
amitlangote09@gmail.com
In reply to: Fabrízio de Royes Mello (#9)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Wed, Jun 19, 2013 at 12:45 PM, Fabrízio de Royes Mello
<fabriziomello@gmail.com> wrote:

On Mon, Jun 17, 2013 at 11:33 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

Replace/alter the object if it already exists, but fail if it does not
exist.

The complete set of variants is:

- object does not exist:

- proceed (normal CREATE)
- error (my above description)

- object exists:

- replace (CREATE OR REPLACE)
- skip (CREATE IF NOT EXISTS)
- error (normal CREATE)

I understood.

The syntax can be like that?
- CREATE [ OR REPLACE | IF NOT EXISTS ] AGGREGATE ...
- CREATE [ OR REPLACE | IF NOT EXISTS ] OPERATOR ...
- CREATE [ OR REPLACE | IF NOT EXISTS ] FUNCTION ...

I can add this features too, but IMHO it is more prudent at this CF we just
implement the IF NOT EXISTS according the initial proposal.

I'm planning another patch do next CF to add support to "IF NOT EXISTS" to
others "CREATE" statements. See my planning [1].

Is it possible to:

CREATE [ OR REPLACE | IF NOT EXISTS ] OPERATOR CLASS

I am in a situation where I need to conditionally create an operator
class (that is, create only if already does not exist).

For example, currently, while trying out pg_trgm and a new external
module pg_bigm, I found that, currently, only one of them can be
installed in a database at a time. pg_bigm for backward compatibility
also creates pg_trgm_ops operator class with its member functions
being the ones implemented by pg_bigm. So, if pg_trgm already exists,
then I won't be able to add pg_bigm (which has its own use cases and
we can probably have the two co-exist) and vice versa. It would be
nice if we had the above feature so that pg_bigm or pg_trgm can use
'IF NOT EXISTS' while creating pg_trgm_ops operator class.

Thoughts?

--
Amit Langote

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

#11Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Amit Langote (#10)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Thu, Jun 20, 2013 at 1:52 AM, Amit Langote <amitlangote09@gmail.com>
wrote:

Is it possible to:

CREATE [ OR REPLACE | IF NOT EXISTS ] OPERATOR CLASS

I am in a situation where I need to conditionally create an operator
class (that is, create only if already does not exist).

[...]

The intention is cover all "CREATE OPERATOR" variants. See my planning [1]https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing.

Regards,

[1]: https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing
https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#12Amit Langote
amitlangote09@gmail.com
In reply to: Fabrízio de Royes Mello (#11)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Thu, Jun 20, 2013 at 9:48 PM, Fabrízio de Royes Mello
<fabriziomello@gmail.com> wrote:

On Thu, Jun 20, 2013 at 1:52 AM, Amit Langote <amitlangote09@gmail.com>
wrote:

Is it possible to:

CREATE [ OR REPLACE | IF NOT EXISTS ] OPERATOR CLASS

I am in a situation where I need to conditionally create an operator
class (that is, create only if already does not exist).

[...]

The intention is cover all "CREATE OPERATOR" variants. See my planning [1].

Regards,

[1]
https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing

Hmm, okay. Last time I checked, the CREATE OPERATOR CLASS row was
empty, so asked.

--
Amit Langote

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

#13Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#3)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Wed, Jun 12, 2013 at 3:00 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

On 6/12/13 1:29 PM, Fabrízio de Royes Mello wrote:

The attached patch add support to "IF NOT EXISTS" to "CREATE" statements
listed below:

- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE CAST [ IF NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TEXT SEARCH {PARSER | DICTIONARY | TEMPLATE | CONFIGURATION} [
IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]

I'm wondering where "IF NOT EXISTS" and "OR REPLACE" will meet.

I kind of don't see the point of having IF NOT EXISTS for things that
have OR REPLACE, and am generally in favor of implementing OR REPLACE
rather than IF NOT EXISTS where possible. The point is usually to get
the object to a known state, and OR REPLACE will generally accomplish
that better than IF NOT EXISTS. However, if the object has complex
structure (like a table that contains data) then "replacing" it is a
bad plan, so IF NOT EXISTS is really the best you can do - and it's
still useful, even if it does require more care.

Btw., I also want REPLACE BUT DO NOT CREATE.

That's a mouthful. What's it good for?

--
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

#14Peter Eisentraut
peter_e@gmx.net
In reply to: Robert Haas (#13)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 6/20/13 11:04 AM, Robert Haas wrote:

I kind of don't see the point of having IF NOT EXISTS for things that
have OR REPLACE, and am generally in favor of implementing OR REPLACE
rather than IF NOT EXISTS where possible.

I tend to agree.

Btw., I also want REPLACE BUT DO NOT CREATE.

That's a mouthful. What's it good for?

If you run an upgrade SQL script that is supposed to replace, say, a
bunch of functions with new versions, you'd want the behavior that it
replaces the existing function if it exists, but errors out if it
doesn't, because then you're perhaps connected to the wrong database.

It's a marginal feature, and I'm not going to pursue it, but if someone
wanted to make the CREATE commands fully featured, there is use for this.

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

#15Andres Freund
andres@2ndquadrant.com
In reply to: Fabrízio de Royes Mello (#2)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 2013-06-12 14:29:59 -0300, Fabrízio de Royes Mello wrote:

On Fri, May 24, 2013 at 12:22 PM, Fabrízio de Royes Mello <
fabriziomello@gmail.com> wrote:

Hi all,

I working in a patch to include support of "IF NOT EXISTS" into "CREATE"
statements that not have it yet.

I started with "DefineStmt" section from "src/backend/parser/gram.y":
- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]
- CREATE TEXT SEARCH {PARSER | DITIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...

The attached patch add support to "IF NOT EXISTS" to "CREATE" statements
listed below:

- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE CAST [ IF NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TEXT SEARCH {PARSER | DICTIONARY | TEMPLATE | CONFIGURATION} [ IF
NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]

I'd argue if we go that way - which seems to be a good idea - we really
ought to make a complete pass and add it to all commands where it's
currently missing.

* CREATE DOMAIN
* CREATE GROUP
* CREATE TABLE AS
* CREATE MATERIALIZED VIEW
* CREATE SEQUENCE (we have ALTER but not CREATE?)
* CREATE TABLESPACE (arguably slightly harder)
* CREATE FOREIGN DATA WRAPPER
* CREATE SERVER
* CREATE DATABASE
* CREATE USER MAPPING
* CREATE TRIGGER
* CREATE EVENT TRIGGER
* CREATE INDEX
* CLUSTER

Cases that seem useful, even though we have OR REPLACE:
* CREATE VIEW
* CREATE FUNCTION

Of dubious use:
* CREATE OPERATOR CLASS
* CREATE OPERATOR FAMILY
* CREATE RULE
* CREATE CONVERSION

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

#16Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Peter Eisentraut (#14)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Thu, Jun 20, 2013 at 1:24 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

On 6/20/13 11:04 AM, Robert Haas wrote:

I kind of don't see the point of having IF NOT EXISTS for things that
have OR REPLACE, and am generally in favor of implementing OR REPLACE
rather than IF NOT EXISTS where possible.

I tend to agree.

I agree if is possible to have OR REPLACE then we must do that, but in
other hands
I don't see a problem if we have support to both IF NOT EXISTS and OR
REPLACE. In
some cases we don't really want to replace the object body if its already
exists so
IF NOT EXISTS is useful to don't break the transaction inside a upgrade
script.

Btw., I also want REPLACE BUT DO NOT CREATE.

That's a mouthful. What's it good for?

If you run an upgrade SQL script that is supposed to replace, say, a
bunch of functions with new versions, you'd want the behavior that it
replaces the existing function if it exists, but errors out if it
doesn't, because then you're perhaps connected to the wrong database.

It's a marginal feature, and I'm not going to pursue it, but if someone
wanted to make the CREATE commands fully featured, there is use for this.

Well, my intention is do that for all CREATE commands.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#17Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Andres Freund (#15)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Mon, Jun 24, 2013 at 8:05 AM, Andres Freund <andres@2ndquadrant.com>
wrote:

I'd argue if we go that way - which seems to be a good idea - we really
ought to make a complete pass and add it to all commands where it's
currently missing.

Yeah... this is my purpose, but I decide do that in two steps. First with
the patch already
sent to CF1 and second with another patch to cover the remaining CREATE
commands.

I created a simple spreadsheet [1]https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing to control my work. Suggestions are
welcome.

* CREATE DOMAIN
* CREATE GROUP
* CREATE TABLE AS
* CREATE MATERIALIZED VIEW
* CREATE SEQUENCE (we have ALTER but not CREATE?)
* CREATE TABLESPACE (arguably slightly harder)
* CREATE FOREIGN DATA WRAPPER
* CREATE SERVER
* CREATE DATABASE
* CREATE USER MAPPING
* CREATE TRIGGER
* CREATE EVENT TRIGGER
* CREATE INDEX
* CLUSTER

Ok.

Cases that seem useful, even though we have OR REPLACE:
* CREATE VIEW
* CREATE FUNCTION

+1

Of dubious use:
* CREATE OPERATOR CLASS
* CREATE OPERATOR FAMILY
* CREATE RULE
* CREATE CONVERSION

In fact I would say that will be seldom used, but I don't see any
problem to implement them.

Regards,

[1]: https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing
https://docs.google.com/spreadsheet/ccc?key=0Ai7oCVcVQiKFdEctQUxNNlR1R2xRTUpJNFNDcFo4MUE&amp;usp=sharing

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#18Abhijit Menon-Sen
ams@2ndQuadrant.com
In reply to: Fabrízio de Royes Mello (#2)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

At 2013-06-12 14:29:59 -0300, fabriziomello@gmail.com wrote:

The attached patch add support to "IF NOT EXISTS" to "CREATE"
statements listed below: […]

I noticed that this patch was listed as "Needs Review" with no
reviewers, so I had a quick look.

It applies with a couple of "trailing whitespace" warnings. Compiles OK.
Documentation changes look fine other than a couple of minor whitespace
errors (literal tabs in some continuation lines).

First, I looked at the changes in src/include: adding if_not_exists to
the relevant parse nodes, and adding ifNotExists parameters to various
functions (e.g. OperatorCreate). The changes look fine. There's a bit
more whitespace quirkiness, though (removed tabs).

Next, changes in src/backend, starting with parser changes: the patch
adds "IF_P NOT EXISTS" variants for various productions. For example:

src/backend/parser/gram.y:4605:

DefineStmt:
CREATE AGGREGATE func_name aggr_args definition
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_AGGREGATE;
n->oldstyle = false;
n->defnames = $3;
n->args = $4;
n->definition = $5;
n->if_not_exists = false;
$$ = (Node *)n;
}
| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_AGGREGATE;
n->oldstyle = false;
n->defnames = $6;
n->args = $7;
n->definition = $8;
n->if_not_exists = true;
$$ = (Node *)n;
}

Although there is plenty of precedent for this kind of doubling of rules
(e.g. CREATE SCHEMA, CREATE EXTENSION), it doesn't strike me as the best
idea. There's an "opt_if_not_exists", and this patch uses it for "CREATE
CAST" (and it was already used for AlterEnumStmt).

I think opt_if_not_exists should be used for the others as well.

Moving on, the patch adds the if_not_exists field to the relevant
functions in {copyfuncs,equalfuncs}.c and adds stmt->if_not_exists
to the calls to DefineAggregate() etc. in tcop/utility.c. Fine.

diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..851c314 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
/* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
-1,			/* typmod */
0,			/* array dimensions for typBaseType */
false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);

Parameter needs a comment.

diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e80b600..4452ba3 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -228,7 +229,7 @@ AggregateCreate(const char *aggName,

procOid = ProcedureCreate(aggName,
aggNamespace,
- false, /* no replacement */
+ false, /* replacement */
false, /* doesn't return a set */
finaltype, /* returnType */
GetUserId(), /* proowner */

What's up with this? We're calling ProcedureCreate with replace==false,
so "no replacement" sounds correct to me.

diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..7466e76 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
Oid restrictionId,
Oid joinId,
bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool if_not_exists)
{
Relation	pg_operator_desc;
HeapTuple	tup;

This should be "ifNotExists" (to match the header file, and all your
other changes).

@@ -416,11 +417,18 @@ OperatorCreate(const char *operatorName,
rightTypeId,
&operatorAlreadyDefined);

-	if (operatorAlreadyDefined)
+	if (operatorAlreadyDefined && !if_not_exists)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FUNCTION),
errmsg("operator %s already exists",
operatorName)));
+	if (operatorAlreadyDefined && if_not_exists) {
+		ereport(NOTICE,
+				(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				 errmsg("operator %s already exists, skipping",
+						operatorName)));
+		return InvalidOid;
+	}

Everywhere else, you're doing something like this:

if (exists)
{
if (!if_not_exists)
ERROR
else
NOTICE
}

So you should do the same thing here. Failing that, at least reorder the
blocks so that you don't test both !if_not_exists and if_not_exists:

if (operatorAlreadyDefined && if_not_exists)
{
NOTICE;
return InvalidOid;
}

if (operatorAlreadyDefined)
ERROR

(But first see below.)

diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..3d55360 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -397,9 +398,20 @@ TypeCreate(Oid newTypeOid,
* shell type, however.
*/
if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", typeName)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", typeName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+		}

I'd strongly prefer to see this written everywhere as follows:

if (already_exists)
{
if (ifNotExists)
{
ereport(NOTICE, …);
heap_close(pg_type_desc, RowExclusiveLock);
return InvalidOid;
}
ereport(ERROR, …);
}

The error can be in an else {} or not, I have only a weak preference in
that matter. But the "if (!ifNotExists)" is pretty awkward. Ultimately,
the patch is adding special handling for a new flag, so it makes sense
to test if the flag is set and behave specially, rather than testing if
it's not set to do what was done before.

(Actually, I like the way AlterEnumStmt calls this "skipIfExists". That
reads much more nicely. But there are enough "if_not_exists" elsewhere
in the code that I won't argue to change them in this patch, at least.)

Sorry to nitpick, but I feel quite strongly about this.

diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
transfuncName,		/* step function name */
finalfuncName,		/* final function name */
sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */

You should settle on "if not exists" or "if not exists flag" for your
comments. I suggest the former (i.e. no "flag").

I don't see any other problems with the patch. It passes "make check".

I'm marking this as "Waiting on Author".

-- Abhijit

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

#19Fabrízio de Royes Mello
fabrizio@timbira.com.br
In reply to: Abhijit Menon-Sen (#18)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Sat, Jul 13, 2013 at 7:21 AM, Abhijit Menon-Sen <ams@2ndquadrant.com>
wrote:

At 2013-06-12 14:29:59 -0300, fabriziomello@gmail.com wrote:

The attached patch add support to "IF NOT EXISTS" to "CREATE"
statements listed below: […]

I noticed that this patch was listed as "Needs Review" with no
reviewers, so I had a quick look.

Abhijit, thanks for your review.

It applies with a couple of "trailing whitespace" warnings. Compiles OK.
Documentation changes look fine other than a couple of minor whitespace
errors (literal tabs in some continuation lines).

First, I looked at the changes in src/include: adding if_not_exists to
the relevant parse nodes, and adding ifNotExists parameters to various
functions (e.g. OperatorCreate). The changes look fine. There's a bit
more whitespace quirkiness, though (removed tabs).

Ok.

Next, changes in src/backend, starting with parser changes: the patch
adds "IF_P NOT EXISTS" variants for various productions. For example:

src/backend/parser/gram.y:4605:

DefineStmt:
CREATE AGGREGATE func_name aggr_args definition
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_AGGREGATE;
n->oldstyle = false;
n->defnames = $3;
n->args = $4;
n->definition = $5;
n->if_not_exists = false;
$ = (Node *)n;
}
| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args

definition

{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_AGGREGATE;
n->oldstyle = false;
n->defnames = $6;
n->args = $7;
n->definition = $8;
n->if_not_exists = true;
$ = (Node *)n;
}

Although there is plenty of precedent for this kind of doubling of rules
(e.g. CREATE SCHEMA, CREATE EXTENSION), it doesn't strike me as the best
idea. There's an "opt_if_not_exists", and this patch uses it for "CREATE
CAST" (and it was already used for AlterEnumStmt).

I think opt_if_not_exists should be used for the others as well.

I could not use the "opt_if_not_exists" because bison emits an error:

/usr/bin/bison -d -o gram.c gram.y
gram.y: conflicts: 10 shift/reduce
gram.y: expected 0 shift/reduce conflicts
make[3]: *** [gram.c] Error 1

I really don't know how to solve this problem. I'm just do ajustments like
that:

CREATE AGGREGATE opt_if_not_exists func_name aggr_args
definition
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_AGGREGATE;
n->oldstyle = false;
n->defnames = $4;
n->args = $5;
n->definition = $6;
n->if_not_exists = $3;
$$ = (Node *)n;
}

I changed all statements to use "opt_if_not_exists" (like above) but bison
do not
accept it.

Looking more carefully at gram.y when we use "IF_P EXISTS" (DROP ROLE IF
EXISTS) all was written using variants of original statement. And exists
the rule
"opt_if_exists" too, that's used in "DROP CAST". Because of this reason I
use
"opt_if_not_exists" in "CREATE CAST".

Moving on, the patch adds the if_not_exists field to the relevant
functions in {copyfuncs,equalfuncs}.c and adds stmt->if_not_exists
to the calls to DefineAggregate() etc. in tcop/utility.c. Fine.

Ok.

diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..851c314 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
/* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
-1,                  /* typmod */
0,                   /* array

dimensions for typBaseType */

false, /* Type NOT NULL

*/

- InvalidOid); /* rowtypes never have a

collation */

+ InvalidOid, /* rowtypes never have a

collation */

+ false);

Parameter needs a comment.

Fixed.

diff --git a/src/backend/catalog/pg_aggregate.c

b/src/backend/catalog/pg_aggregate.c

index e80b600..4452ba3 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -228,7 +229,7 @@ AggregateCreate(const char *aggName,

procOid = ProcedureCreate(aggName,
aggNamespace,
- false,

/* no replacement */

+ false,

/* replacement */

false,

/* doesn't return a set */

finaltype,

/* returnType */

GetUserId(),

/* proowner */

What's up with this? We're calling ProcedureCreate with replace==false,
so "no replacement" sounds correct to me.

Fixed.

diff --git a/src/backend/catalog/pg_operator.c

b/src/backend/catalog/pg_operator.c

index 3c4fedb..7466e76 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
Oid restrictionId,
Oid joinId,
bool canMerge,
-                        bool canHash)
+                        bool canHash,
+                        bool if_not_exists)
{
Relation        pg_operator_desc;
HeapTuple       tup;

This should be "ifNotExists" (to match the header file, and all your
other changes).

Fixed.

@@ -416,11 +417,18 @@ OperatorCreate(const char *operatorName,

rightTypeId,

&operatorAlreadyDefined);

-     if (operatorAlreadyDefined)
+     if (operatorAlreadyDefined && !if_not_exists)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FUNCTION),
errmsg("operator %s already exists",
operatorName)));
+     if (operatorAlreadyDefined && if_not_exists) {
+             ereport(NOTICE,
+                             (errcode(ERRCODE_DUPLICATE_FUNCTION),
+                              errmsg("operator %s already exists,

skipping",

+                                             operatorName)));
+             return InvalidOid;
+     }

Everywhere else, you're doing something like this:

if (exists)
{
if (!if_not_exists)
ERROR
else
NOTICE
}

So you should do the same thing here. Failing that, at least reorder the
blocks so that you don't test both !if_not_exists and if_not_exists:

if (operatorAlreadyDefined && if_not_exists)
{
NOTICE;
return InvalidOid;
}

if (operatorAlreadyDefined)
ERROR

(But first see below.)

Fixed.

diff --git a/src/backend/catalog/pg_type.c

b/src/backend/catalog/pg_type.c

index 23ac3dd..3d55360 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -397,9 +398,20 @@ TypeCreate(Oid newTypeOid,
* shell type, however.
*/
if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
-                     ereport(ERROR,
-

(errcode(ERRCODE_DUPLICATE_OBJECT),

- errmsg("type \"%s\" already

exists", typeName)));

+             {
+                     if (!ifNotExists)
+                             ereport(ERROR,
+

(errcode(ERRCODE_DUPLICATE_OBJECT),

+ errmsg("type \"%s\"

already exists", typeName)));

+                     else
+                     {
+                             ereport(NOTICE,
+

(errcode(ERRCODE_DUPLICATE_OBJECT),

+ errmsg("type \"%s\"

already exists, skipping", typeName)));

+ heap_close(pg_type_desc,

RowExclusiveLock);

+                             return InvalidOid;
+                     }
+             }

I'd strongly prefer to see this written everywhere as follows:

if (already_exists)
{
if (ifNotExists)
{
ereport(NOTICE, …);
heap_close(pg_type_desc, RowExclusiveLock);
return InvalidOid;
}
ereport(ERROR, …);
}

The error can be in an else {} or not, I have only a weak preference in
that matter. But the "if (!ifNotExists)" is pretty awkward. Ultimately,
the patch is adding special handling for a new flag, so it makes sense
to test if the flag is set and behave specially, rather than testing if
it's not set to do what was done before.

Fixed.

(Actually, I like the way AlterEnumStmt calls this "skipIfExists". That
reads much more nicely. But there are enough "if_not_exists" elsewhere
in the code that I won't argue to change them in this patch, at least.)

You all right, and in other places we have "missing_ok".

When I finish this patch and the next one (to add IF NOT EXISTS to
remaining CREATE statements) I send a patch to normalize that.

Sorry to nitpick, but I feel quite strongly about this.

diff --git a/src/backend/commands/aggregatecmds.c

b/src/backend/commands/aggregatecmds.c

index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool

oldstyle, List *parameters)

transfuncName,

/* step function name */

finalfuncName,

/* final function name */

sortoperatorName,

/* sort operator name */

- transTypeId, /*

transition data type */

- initval); /*

initial condition */

+ transTypeId, /*

transition data type */

+ initval,

/* initial condition */

+ ifNotExists);

/* if not exists flag */

You should settle on "if not exists" or "if not exists flag" for your
comments. I suggest the former (i.e. no "flag").

Fixed.

I don't see any other problems with the patch. It passes "make check".

I'm marking this as "Waiting on Author".

And now I'm marking this as "Needs Review" (again) ;-)

Regards,

--
Fabrízio de Royes Mello Timbira - http://www.timbira.com.br/
PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento

Attachments:

create_if_not_exists_v2.patchapplication/octet-stream; name=create_if_not_exists_v2.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..26cb127 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e80b600..18268e7 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..949bb23 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -416,6 +417,16 @@ OperatorCreate(const char *operatorName,
 								   rightTypeId,
 								   &operatorAlreadyDefined);
 
+	/* skip if already exists */
+	if (operatorAlreadyDefined && ifNotExists)
+	{
+		ereport(NOTICE,
+				(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				 errmsg("operator %s already exists, skipping",
+						operatorName)));
+		return InvalidOid;
+	}
+
 	if (operatorAlreadyDefined)
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..ef03cfd 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				errmsg("function \"%s\" already exists with same argument types",
+					   procedureName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..1deb1fb 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,26 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("cast from type %s to type %s already exists",
-						format_type_be(sourcetypeid),
-						format_type_be(targettypeid))));
+	{
+		if (!stmt->if_not_exists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..6a28401 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,31 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +423,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +437,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+							dictnamespace,
+							dictname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +769,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +790,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1023,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1033,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1043,39 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists",
+							cfgnamespace,
+							cfgname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+	}
+
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..2ed65f6 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,20 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +596,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +636,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -1011,7 +1027,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   false);		/* if not exists flag */
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1101,20 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1151,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1195,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1335,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", typeName)));
+		{
+			if (!stmt->if_not_exists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", typeName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/*
@@ -1457,7 +1500,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1545,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1617,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2067,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2103,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b5b8d63..7d71d7a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2763,6 +2763,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3022,6 +3023,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3033,6 +3035,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3044,6 +3047,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3658,6 +3662,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3f96595..75e0c44 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1117,6 +1117,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1338,6 +1339,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1347,6 +1349,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1356,6 +1359,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1874,6 +1878,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f67ef0c..85ec323 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4611,6 +4611,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4622,6 +4634,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4632,6 +4657,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4642,6 +4679,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4653,6 +4702,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4662,6 +4724,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4669,6 +4742,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4676,6 +4758,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4685,6 +4776,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4694,6 +4796,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4703,6 +4816,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4712,6 +4836,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4721,6 +4856,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4730,6 +4876,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4831,8 +4988,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6700,37 +6857,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index de22dff..2f72770 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1876,6 +1876,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -2290,6 +2291,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2301,6 +2303,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2312,6 +2315,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2572,6 +2576,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 1d7e524..9095ddb 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -406,6 +406,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -430,6 +434,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 04c5cc1..2ee71f9 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -334,6 +334,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -354,6 +356,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#20Martijn van Oosterhout
kleptog@svana.org
In reply to: Fabrízio de Royes Mello (#19)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Sun, Jul 14, 2013 at 03:36:09AM -0300, Fabrízio de Royes Mello wrote:

Next, changes in src/backend, starting with parser changes: the patch
adds "IF_P NOT EXISTS" variants for various productions. For example:

<snip>

I think opt_if_not_exists should be used for the others as well.

I could not use the "opt_if_not_exists" because bison emits an error:

/usr/bin/bison -d -o gram.c gram.y
gram.y: conflicts: 10 shift/reduce
gram.y: expected 0 shift/reduce conflicts
make[3]: *** [gram.c] Error 1

I really don't know how to solve this problem. I'm just do ajustments like
that:

This probably isn't solvable, which is why the coding is double in many
existing places. The issue is that by using opt_if_not_exists you make
that bison has to decide much earlier which rule it is parsing. Bison
only has one token lookahead and if that's not enough you get errors.

BTW, bison dumps a large file describing all its states that you should
be able to work out from that where the exact problem lies.

Have a nice day,
--
Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/

He who writes carelessly confesses thereby at the very outset that he does
not attach much importance to his own thoughts.

-- Arthur Schopenhauer

#21Karol Trzcionka
karlikt@gmail.com
In reply to: Fabrízio de Royes Mello (#19)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

Hello,
patch works fine but is there any reason to comparing each ifNotExists
in different way?
i.e.
ProcedureCreate
if (!ifNotExists)
...
else
{
...
return
}
----
TypeCreate
if (ifNotExists)
{
...
return
}
...
---
Shouldn't it be more consistent?
Regards,
Karol

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

#22Fabrízio de Royes Mello
fabrizio@timbira.com.br
In reply to: Karol Trzcionka (#21)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 24-07-2013 14:49, Karol Trzcionka wrote:

Hello,
patch works fine but is there any reason to comparing each ifNotExists
in different way?
i.e.
ProcedureCreate
if (!ifNotExists)
...
else
{
...
return
}
----
TypeCreate
if (ifNotExists)
{
...
return
}
...
---
Shouldn't it be more consistent?

Should be... I fix that in attached patch.

Regards,

--
Fabr�zio de Royes Mello Timbira - http://www.timbira.com.br/
PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento

Attachments:

create_if_not_exists_v3.patchtext/x-patch; name=create_if_not_exists_v3.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..26cb127 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 480c17c..fecc994 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..949bb23 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -416,6 +417,16 @@ OperatorCreate(const char *operatorName,
 								   rightTypeId,
 								   &operatorAlreadyDefined);
 
+	/* skip if already exists */
+	if (operatorAlreadyDefined && ifNotExists)
+	{
+		ereport(NOTICE,
+				(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				 errmsg("operator %s already exists, skipping",
+						operatorName)));
+		return InvalidOid;
+	}
+
 	if (operatorAlreadyDefined)
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..fd3b655 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+					 errmsg("function \"%s\" already exists with same argument types",
+							procedureName)));
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..1deb1fb 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,26 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("cast from type %s to type %s already exists",
-						format_type_be(sourcetypeid),
-						format_type_be(targettypeid))));
+	{
+		if (!stmt->if_not_exists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..6a28401 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,31 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +423,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +437,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+							dictnamespace,
+							dictname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +769,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +790,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1023,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1033,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1043,39 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (!ifNotExists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists",
+							cfgnamespace,
+							cfgname)));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+	}
+
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..2ed65f6 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,20 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +596,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +636,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -1011,7 +1027,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   false);		/* if not exists flag */
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1101,20 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1151,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1195,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1335,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", typeName)));
+		{
+			if (!stmt->if_not_exists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", typeName)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/*
@@ -1457,7 +1500,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1545,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1617,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2067,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2103,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
-			ereport(ERROR,
-					(errcode(ERRCODE_DUPLICATE_OBJECT),
-					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		{
+			if (!ifNotExists)
+				ereport(ERROR,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+			else
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bcc6496..bdf3325 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2780,6 +2780,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3039,6 +3040,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3050,6 +3052,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3061,6 +3064,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3677,6 +3681,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7f9737e..c2acfe5 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1120,6 +1120,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1341,6 +1342,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1350,6 +1352,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1359,6 +1362,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1879,6 +1883,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8d2bdf..7fa9dea 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4613,6 +4613,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4624,6 +4636,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4634,6 +4659,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4644,6 +4681,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4655,6 +4704,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4664,6 +4726,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4671,6 +4744,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4678,6 +4760,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4687,6 +4778,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4696,6 +4798,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4705,6 +4818,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4714,6 +4838,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4723,6 +4858,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4732,6 +4878,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4833,8 +4990,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6702,37 +6859,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b4013e8..aa3bed5 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1898,6 +1898,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -2312,6 +2313,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2323,6 +2325,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2334,6 +2337,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2603,6 +2607,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 4e4df0c..6f2becf 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -581,6 +581,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -605,6 +609,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index d62f64f..f225ade 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -501,6 +501,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -521,6 +523,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#23Karol Trzcionka
karlikt@gmail.com
In reply to: Fabrízio de Royes Mello (#22)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

W dniu 26.07.2013 02:44, Fabr�zio de Royes Mello pisze:

Should be... I fix that in attached patch.

Hello, as I can see there are more inconsistent places.
First style:
OperatorCreate
---
Second style:
ProcedureCreate
TypeCreate
DefineTSParser
DefineType
DefineEnum
---
Third style:
CreateCast
DefineTSDictionary
DefineTSTemplate
DefineTSConfiguration
DefineRange
DefineCompositeType
Regards,
Karol

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

#24Fabrízio de Royes Mello
fabrizio@timbira.com.br
In reply to: Karol Trzcionka (#23)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 26-07-2013 05:39, Karol Trzcionka wrote:

W dniu 26.07.2013 02:44, Fabr�zio de Royes Mello pisze:

Should be... I fix that in attached patch.

Hello, as I can see there are more inconsistent places.
First style:
OperatorCreate
---

This style is already right :

if ( ifNotExists )
{
skip
return
}
error

Second style:
ProcedureCreate
TypeCreate
DefineTSParser
DefineType
DefineEnum
---
Third style:
CreateCast
DefineTSDictionary
DefineTSTemplate
DefineTSConfiguration
DefineRange
DefineCompositeType

Fixed... thanks.

Regards,

--
Fabr�zio de Royes Mello Timbira - http://www.timbira.com.br/
PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento

Attachments:

create_if_not_exists_v4.patchtext/x-patch; name=create_if_not_exists_v4.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..26cb127 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 480c17c..fecc994 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..949bb23 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -416,6 +417,16 @@ OperatorCreate(const char *operatorName,
 								   rightTypeId,
 								   &operatorAlreadyDefined);
 
+	/* skip if already exists */
+	if (operatorAlreadyDefined && ifNotExists)
+	{
+		ereport(NOTICE,
+				(errcode(ERRCODE_DUPLICATE_FUNCTION),
+				 errmsg("operator %s already exists, skipping",
+						operatorName)));
+		return InvalidOid;
+	}
+
 	if (operatorAlreadyDefined)
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..fd3b655 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+					 errmsg("function \"%s\" already exists with same argument types",
+							procedureName)));
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..1deb1fb 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,26 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("cast from type %s to type %s already exists",
-						format_type_be(sourcetypeid),
-						format_type_be(targettypeid))));
+	{
+		if (!stmt->if_not_exists)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+		else
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..4885ed8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,31 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +423,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +437,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+						dictnamespace,
+						dictname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +769,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +790,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search template \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						tmplname)));
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1023,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1033,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1043,38 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search configuration \"%s\".\"%s\" already exists",
+						cfgnamespace,
+						cfgname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..cc9cfb0 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,20 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +596,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +636,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -1011,7 +1027,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   false);		/* if not exists flag */
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1101,20 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1151,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1195,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1335,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/*
@@ -1457,7 +1500,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1545,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1617,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2067,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2103,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bcc6496..bdf3325 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2780,6 +2780,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3039,6 +3040,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3050,6 +3052,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3061,6 +3064,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3677,6 +3681,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7f9737e..c2acfe5 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1120,6 +1120,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1341,6 +1342,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1350,6 +1352,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1359,6 +1362,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1879,6 +1883,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8d2bdf..7fa9dea 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4613,6 +4613,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4624,6 +4636,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4634,6 +4659,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4644,6 +4681,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4655,6 +4704,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4664,6 +4726,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4671,6 +4744,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4678,6 +4760,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4687,6 +4778,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4696,6 +4798,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4705,6 +4818,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4714,6 +4838,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4723,6 +4858,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4732,6 +4878,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4833,8 +4990,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6702,37 +6859,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b4013e8..aa3bed5 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1898,6 +1898,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -2312,6 +2313,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2323,6 +2325,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2334,6 +2337,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2603,6 +2607,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 4e4df0c..6f2becf 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -581,6 +581,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -605,6 +609,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index d62f64f..f225ade 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -501,6 +501,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -521,6 +523,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#25Abhijit Menon-Sen
ams@2ndQuadrant.com
In reply to: Karol Trzcionka (#23)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

At 2013-07-26 10:39:00 +0200, karlikt@gmail.com wrote:

Hello, as I can see there are more inconsistent places.

Right. This is what I was referring to in my original review. All of the
relevant sites (pre-patch) that currently do:

if (already exists)
ereport(ERROR …)

should instead be made to do:

if (already exists)
{
if (ifNotExists)
{
ereport(NOTICE …)
return
}

ereport(ERROR …)
}

or even (very slightly easier to review):

if (already exists && ifNotExists)
{
ereport(ERROR …)
return
}

if (already exists)
ereport(ERROR …)

I don't care much which of the two is used, so long as it's (a) the same
everywhere, and (b) there's no "if (!ifNot" anywhere.

-- Abhijit

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

#26Abhijit Menon-Sen
ams@2ndQuadrant.com
In reply to: Fabrízio de Royes Mello (#24)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

At 2013-07-26 18:55:21 -0300, fabrizio@timbira.com.br wrote:

Fixed... thanks.

Ah, sorry. I didn't see this patch immediately because you dropped me
from the Cc: list.

You missed a couple of places. Updated patch attached.

This is now ready for committer, I reckon.

-- Abhijit

Attachments:

if-not-exists.difftext/x-diff; charset=us-asciiDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..a4277e8 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 }
 
 /* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 480c17c..fecc994 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..d87c32c 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -417,10 +418,21 @@ OperatorCreate(const char *operatorName,
 								   &operatorAlreadyDefined);
 
 	if (operatorAlreadyDefined)
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_FUNCTION),
+					 errmsg("operator %s already exists, skipping",
+							operatorName)));
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
 				 errmsg("operator %s already exists",
 						operatorName)));
+	}
 
 	/*
 	 * At this point, if operatorObjectId is not InvalidOid then we are
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..fd3b655 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+					 errmsg("function \"%s\" already exists with same argument types",
+							procedureName)));
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..8d89380 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists */
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..4fa42e2 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,26 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
+	{
+		if (stmt->if_not_exists)
+               {
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+               }
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("cast from type %s to type %s already exists",
 						format_type_be(sourcetypeid),
 						format_type_be(targettypeid))));
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..6c230b4 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..cb6ace2 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,30 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +422,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +436,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+						dictnamespace,
+						dictname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +768,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +789,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search template \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						tmplname)));
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1022,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1032,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1042,38 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search configuration \"%s\".\"%s\" already exists",
+						cfgnamespace,
+						cfgname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..6641635 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,19 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +595,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +635,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists */
 
 	pfree(array_type);
 
@@ -1011,7 +1026,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   false);		/* if not exists */
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1100,19 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1149,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1193,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1333,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/*
@@ -1457,7 +1498,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1543,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1615,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2065,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2101,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bcc6496..bdf3325 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2780,6 +2780,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3039,6 +3040,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3050,6 +3052,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3061,6 +3064,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3677,6 +3681,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7f9737e..c2acfe5 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1120,6 +1120,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1341,6 +1342,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1350,6 +1352,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1359,6 +1362,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1879,6 +1883,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8d2bdf..7fa9dea 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4613,6 +4613,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4624,6 +4636,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4634,6 +4659,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4644,6 +4681,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4655,6 +4704,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4664,6 +4726,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4671,6 +4744,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4678,6 +4760,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4687,6 +4778,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4696,6 +4798,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4705,6 +4818,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4714,6 +4838,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4723,6 +4858,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4732,6 +4878,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4833,8 +4990,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6702,37 +6859,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b4013e8..aa3bed5 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1898,6 +1898,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -2312,6 +2313,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2323,6 +2325,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2334,6 +2337,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2603,6 +2607,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 4e4df0c..6f2becf 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -581,6 +581,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -605,6 +609,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index d62f64f..f225ade 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -501,6 +501,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -521,6 +523,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#27Fabrízio de Royes Mello
fabrizio@timbira.com.br
In reply to: Abhijit Menon-Sen (#26)
1 attachment(s)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 26-07-2013 23:57, Abhijit Menon-Sen wrote:

At 2013-07-26 18:55:21 -0300, fabrizio@timbira.com.br wrote:

Fixed... thanks.

Ah, sorry. I didn't see this patch immediately because you dropped me
from the Cc: list.

I'm sorry... unfortunately this patch was moved do CF2 [1]https://commitfest.postgresql.org/action/patch_view?id=1133

You missed a couple of places. Updated patch attached.

You all right... I just fix some spaces and comments on code.

This is now ready for committer, I reckon.

Can you send a comment to this patch on commitfest [1]https://commitfest.postgresql.org/action/patch_view?id=1133 ?

Regards,

[1]: https://commitfest.postgresql.org/action/patch_view?id=1133

--
Fabr�zio de Royes Mello Timbira - http://www.timbira.com.br/
PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento

Attachments:

create_if_not_exists_v5.patchtext/x-patch; name=create_if_not_exists_v5.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..26cb127 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1219,7 +1220,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 480c17c..fecc994 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..47fcb4f 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -417,10 +418,22 @@ OperatorCreate(const char *operatorName,
 								   &operatorAlreadyDefined);
 
 	if (operatorAlreadyDefined)
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_FUNCTION),
+					 errmsg("operator %s already exists, skipping",
+							operatorName)));
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
 				 errmsg("operator %s already exists",
 						operatorName)));
+	}
 
 	/*
 	 * At this point, if operatorObjectId is not InvalidOid then we are
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..fd3b655 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+					 errmsg("function \"%s\" already exists with same argument types",
+							procedureName)));
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..488dba2 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,27 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
+	{
+		/* skip if already exists */
+		if (stmt->if_not_exists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("cast from type %s to type %s already exists",
 						format_type_be(sourcetypeid),
 						format_type_be(targettypeid))));
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..4885ed8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,31 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +423,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +437,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+						dictnamespace,
+						dictname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +769,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +790,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search template \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						tmplname)));
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1023,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1033,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1043,38 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search configuration \"%s\".\"%s\" already exists",
+						cfgnamespace,
+						cfgname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..cc9cfb0 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,20 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +596,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +636,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -1011,7 +1027,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   false);		/* if not exists flag */
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1101,20 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1151,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1195,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1335,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/*
@@ -1457,7 +1500,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1545,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1617,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2067,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2103,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bcc6496..bdf3325 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2780,6 +2780,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3039,6 +3040,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3050,6 +3052,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3061,6 +3064,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3677,6 +3681,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7f9737e..c2acfe5 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1120,6 +1120,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1341,6 +1342,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1350,6 +1352,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1359,6 +1362,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1879,6 +1883,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8d2bdf..7fa9dea 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4613,6 +4613,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4624,6 +4636,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4634,6 +4659,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4644,6 +4681,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4655,6 +4704,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4664,6 +4726,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4671,6 +4744,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4678,6 +4760,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4687,6 +4778,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4696,6 +4798,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4705,6 +4818,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4714,6 +4838,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4723,6 +4858,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4732,6 +4878,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4833,8 +4990,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6702,37 +6859,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b4013e8..aa3bed5 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1898,6 +1898,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -2312,6 +2313,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2323,6 +2325,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2334,6 +2337,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2603,6 +2607,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 4e4df0c..6f2becf 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -581,6 +581,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -605,6 +609,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index d62f64f..f225ade 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -501,6 +501,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -521,6 +523,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#28Fabrízio de Royes Mello
fabrizio@timbira.com.br
In reply to: Abhijit Menon-Sen (#25)
1 attachment(s)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 26-07-2013 23:31, Abhijit Menon-Sen wrote:

At 2013-07-26 10:39:00 +0200, karlikt@gmail.com wrote:

Hello, as I can see there are more inconsistent places.

Right. This is what I was referring to in my original review. All of the
relevant sites (pre-patch) that currently do:

[...]

Hi all,

I'm sending, from the PGBR2013 (The Brazilian PostgreSQL Conference)
[1]: http://pgbr.postgresql.org.br/2013/noticias.php

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]

Soon I'll sent the third and final part to finish this patch.

Regards,

[1]: http://pgbr.postgresql.org.br/2013/noticias.php

--
Fabrízio de Royes Mello Timbira - http://www.timbira.com.br/
PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento

Attachments:

create_if_not_exists_v6.patchtext/x-patch; name=create_if_not_exists_v6.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml
index 49db069..186da16 100644
--- a/doc/src/sgml/ref/create_domain.sgml
+++ b/doc/src/sgml/ref/create_domain.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replaceable class="parameter">data_type</replaceable>
+CREATE DOMAIN [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> [ AS ] <replaceable class="parameter">data_type</replaceable>
     [ COLLATE <replaceable>collation</replaceable> ]
     [ DEFAULT <replaceable>expression</replaceable> ]
     [ <replaceable class="PARAMETER">constraint</replaceable> [ ... ] ]
@@ -69,6 +69,16 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
  <refsect1>
   <title>Parameters</title>
 
+    <varlistentry>
+     <term><literal>IF NOT EXISTS</literal></term>
+     <listitem>
+      <para>
+       Do nothing (except issuing a notice) if a domain with the same name
+       already exists.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <variablelist>
      <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
diff --git a/doc/src/sgml/ref/create_event_trigger.sgml b/doc/src/sgml/ref/create_event_trigger.sgml
index ed66322..cb20a67 100644
--- a/doc/src/sgml/ref/create_event_trigger.sgml
+++ b/doc/src/sgml/ref/create_event_trigger.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
+CREATE EVENT TRIGGER [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable>
   ON <replaceable class="PARAMETER">event</replaceable>
   [ WHEN <replaceable class="PARAMETER">filter_variable</replaceable> IN (filter_value [, ... ]) [ AND ... ] ]
   EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable>()
@@ -44,6 +44,16 @@ CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
  <refsect1>
   <title>Parameters</title>
 
+  <varlistentry>
+   <term><literal>IF NOT EXISTS</literal></term>
+   <listitem>
+    <para>
+     Do nothing (except issuing a notice) if a event trigger the
+     same name already exists.
+    </para>
+   </listitem>
+  </varlistentry>
+
   <variablelist>
    <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml
index 38d160d..982ffe3 100644
--- a/doc/src/sgml/ref/create_sequence.sgml
+++ b/doc/src/sgml/ref/create_sequence.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE [ TEMPORARY | TEMP ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
+CREATE [ TEMPORARY | TEMP ] [ IF NOT EXISTS ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
     [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ]
@@ -90,6 +90,16 @@ SELECT * FROM <replaceable>name</replaceable>;
    </varlistentry>
 
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a sequence with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
@@ -343,8 +353,8 @@ END;
     </listitem>
     <listitem>
      <para>
-      The <literal>OWNED BY</> clause is a <productname>PostgreSQL</>
-      extension.
+      The <literal>OWNED BY</> and <literal>IF NOT EXISTS</> clause
+      is a <productname>PostgreSQL</> extension.
      </para>
     </listitem>
    </itemizedlist></para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index cee72c1..aca9964 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -249,6 +249,7 @@ Boot_CreateStmt:
 													  (Datum) 0,
 													  false,
 													  true,
+													  false,
 													  false);
 						elog(DEBUG4, "relation created with OID %u", id);
 					}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..57f7056 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1016,7 +1017,8 @@ heap_create_with_catalog(const char *relname,
 						 Datum reloptions,
 						 bool use_user_acl,
 						 bool allow_system_table_mods,
-						 bool is_internal)
+						 bool is_internal,
+						 bool ifNotExists)
 {
 	Relation	pg_class_desc;
 	Relation	new_rel_desc;
@@ -1041,9 +1043,20 @@ heap_create_with_catalog(const char *relname,
 	 */
 	existing_relid = get_relname_relid(relname, relnamespace);
 	if (existing_relid != InvalidOid)
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_TABLE),
+					 errmsg("relation \"%s\" already exists, skipping", relname)));
+			heap_close(pg_class_desc, RowExclusiveLock);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
 				 errmsg("relation \"%s\" already exists", relname)));
+	}
 
 	/*
 	 * Since we are going to create a rowtype as well, also check for
@@ -1219,7 +1232,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b73ee4f..6fd659d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -695,7 +695,8 @@ index_create(Relation heapRelation,
 			 bool allow_system_table_mods,
 			 bool skip_build,
 			 bool concurrent,
-			 bool is_internal)
+			 bool is_internal,
+			 bool ifNotExists)
 {
 	Oid			heapRelationId = RelationGetRelid(heapRelation);
 	Relation	pg_class;
@@ -771,10 +772,22 @@ index_create(Relation heapRelation,
 		elog(ERROR, "shared relations must be placed in pg_global tablespace");
 
 	if (get_relname_relid(indexRelationName, namespaceId))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_TABLE),
+					 errmsg("relation \"%s\" already exists, skipping",
+							indexRelationName)));
+			heap_close(pg_class, RowExclusiveLock);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
 				 errmsg("relation \"%s\" already exists",
 						indexRelationName)));
+	}
 
 	/*
 	 * construct tuple descriptor for index tuples
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 480c17c..fecc994 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..47fcb4f 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -417,10 +418,22 @@ OperatorCreate(const char *operatorName,
 								   &operatorAlreadyDefined);
 
 	if (operatorAlreadyDefined)
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_FUNCTION),
+					 errmsg("operator %s already exists, skipping",
+							operatorName)));
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
 				 errmsg("operator %s already exists",
 						operatorName)));
+	}
 
 	/*
 	 * At this point, if operatorObjectId is not InvalidOid then we are
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..fd3b655 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+					 errmsg("function \"%s\" already exists with same argument types",
+							procedureName)));
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 385d64d..441342e 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -228,7 +228,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
 										   reloptions,
 										   false,
 										   true,
-										   true);
+										   true,
+										   false);
 	Assert(toast_relid != InvalidOid);
 
 	/* make the toast relation visible, else heap_open will fail */
@@ -281,7 +282,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
 				 rel->rd_rel->reltablespace,
 				 collationObjectId, classObjectId, coloptions, (Datum) 0,
 				 true, false, false, false,
-				 true, false, false, true);
+				 true, false, false, true,
+				 false);
 
 	heap_close(toast_rel, NoLock);
 
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 051b806..151dc6b 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -686,7 +686,8 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
 										  reloptions,
 										  false,
 										  true,
-										  true);
+										  true,
+										  false);
 	Assert(OIDNewHeap != InvalidOid);
 
 	ReleaseSysCache(tuple);
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 328e2a8..8e9a689 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -189,10 +189,22 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
 	 */
 	tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
 	if (HeapTupleIsValid(tuple))
+	{
+		if (stmt->if_not_exists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("event trigger \"%s\" already exists, skipping",
+							stmt->trigname)));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("event trigger \"%s\" already exists",
 						stmt->trigname)));
+	}
 
 	/* Find and validate the trigger function. */
 	funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..488dba2 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,27 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
+	{
+		/* skip if already exists */
+		if (stmt->if_not_exists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("cast from type %s to type %s already exists",
 						format_type_be(sourcetypeid),
 						format_type_be(targettypeid))));
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 902daa0..e20bd0d 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -601,7 +601,14 @@ DefineIndex(IndexStmt *stmt,
 					 stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
 					 allowSystemTableMods,
 					 skip_build || stmt->concurrent,
-					 stmt->concurrent, !check_rights);
+					 stmt->concurrent, !check_rights,
+					 stmt->if_not_exists);
+
+	if (!OidIsValid(indexRelationId))
+	{
+		heap_close(rel, NoLock);
+		return indexRelationId;
+	}
 
 	/* Add any requested comment */
 	if (stmt->idxcomment != NULL)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index ddfaf3b..5e89b39 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -213,9 +213,13 @@ DefineSequence(CreateSeqStmt *seq)
 	stmt->options = NIL;
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
-	stmt->if_not_exists = false;
+	stmt->if_not_exists = seq->if_not_exists;
 
 	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
+
+	if (seq->if_not_exists && !OidIsValid(seqoid))
+		return InvalidOid;
+
 	Assert(seqoid != InvalidOid);
 
 	rel = heap_open(seqoid, AccessExclusiveLock);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index adc74dd..e4099bd 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -643,7 +643,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 										  reloptions,
 										  true,
 										  allowSystemTableMods,
-										  false);
+										  false,
+										  stmt->if_not_exists);
+
+	if (!OidIsValid(relationId))
+		return relationId;
 
 	/* Store inheritance information for new rel. */
 	StoreCatalogInheritance(relationId, inheritOids);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..4885ed8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,31 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +423,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +437,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+						dictnamespace,
+						dictname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +769,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +790,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search template \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						tmplname)));
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1023,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1033,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1043,38 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search configuration \"%s\".\"%s\" already exists",
+						cfgnamespace,
+						cfgname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..2a00dfb 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,20 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +596,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +636,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -733,9 +749,19 @@ DefineDomain(CreateDomainStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", domainName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", domainName)));
+		}
 	}
 
 	/*
@@ -1011,7 +1037,14 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   stmt->if_not_exists);	/* if not exists flag */
+
+	if (!OidIsValid(domainoid))
+	{
+		ReleaseSysCache(typeTup);
+		return domainoid;
+	}
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1117,20 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1167,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1211,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1351,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/*
@@ -1457,7 +1516,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1561,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1633,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2083,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2119,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 573ffe2..3c8752e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2782,6 +2782,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -2875,6 +2876,7 @@ _copyIndexStmt(const IndexStmt *from)
 	COPY_SCALAR_FIELD(deferrable);
 	COPY_SCALAR_FIELD(initdeferred);
 	COPY_SCALAR_FIELD(concurrent);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3041,6 +3043,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3052,6 +3055,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3063,6 +3067,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3115,6 +3120,7 @@ _copyCreateDomainStmt(const CreateDomainStmt *from)
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(collClause);
 	COPY_NODE_FIELD(constraints);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3679,6 +3685,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 72899fe..96f00c6 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1119,6 +1119,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1340,6 +1341,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1349,6 +1351,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1358,6 +1361,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1402,6 +1406,7 @@ _equalCreateDomainStmt(const CreateDomainStmt *a, const CreateDomainStmt *b)
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(collClause);
 	COMPARE_NODE_FIELD(constraints);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1537,6 +1542,7 @@ _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(ownerId);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1878,6 +1884,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 22e82ba..fc4b671 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3328,6 +3328,17 @@ CreateSeqStmt:
 					n->sequence = $4;
 					n->options = $5;
 					n->ownerId = InvalidOid;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList
+				{
+					CreateSeqStmt *n = makeNode(CreateSeqStmt);
+					$7->relpersistence = $2;
+					n->sequence = $7;
+					n->options = $8;
+					n->ownerId = InvalidOid;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4501,6 +4512,18 @@ CreateEventTrigStmt:
 					n->eventname = $6;
 					n->whenclause = NULL;
 					n->funcname = $9;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+		  | CREATE EVENT TRIGGER IF_P NOT EXISTS name ON ColLabel
+			EXECUTE PROCEDURE func_name '(' ')'
+				{
+					CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
+					n->trigname = $7;
+					n->eventname = $9;
+					n->whenclause = NULL;
+					n->funcname = $12;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		  | CREATE EVENT TRIGGER name ON ColLabel
@@ -4512,6 +4535,19 @@ CreateEventTrigStmt:
 					n->eventname = $6;
 					n->whenclause = $8;
 					n->funcname = $11;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+		  | CREATE EVENT TRIGGER IF_P NOT EXISTS name ON ColLabel
+			WHEN event_trigger_when_list
+			EXECUTE PROCEDURE func_name '(' ')'
+				{
+					CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
+					n->trigname = $7;
+					n->eventname = $9;
+					n->whenclause = $11;
+					n->funcname = $14;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4612,6 +4648,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4623,6 +4671,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4633,6 +4694,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4643,6 +4716,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4654,6 +4739,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4663,6 +4761,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4670,6 +4779,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4677,6 +4795,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4686,6 +4813,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4695,6 +4833,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4704,6 +4853,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4713,6 +4873,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4722,6 +4893,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4731,6 +4913,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4832,8 +5025,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6106,6 +6299,7 @@ IndexStmt:	CREATE opt_unique INDEX opt_concurrently opt_index_name
 					n->isconstraint = false;
 					n->deferrable = false;
 					n->initdeferred = false;
+					n->if_not_exists = false;
 					$$ = (Node *)n;
 				}
 		;
@@ -6701,37 +6895,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
@@ -8252,10 +8449,21 @@ CreateDomainStmt:
 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
 					n->domainname = $3;
 					n->typeName = $5;
+					n->if_not_exists = false;
 					SplitColQualList($6, &n->constraints, &n->collClause,
 									 yyscanner);
 					$$ = (Node *)n;
 				}
+			| CREATE DOMAIN_P IF_P NOT EXISTS any_name opt_as Typename ColQualList
+				{
+					CreateDomainStmt *n = makeNode(CreateDomainStmt);
+					n->domainname = $6;
+					n->typeName = $8;
+					n->if_not_exists = true;
+					SplitColQualList($9, &n->constraints, &n->collClause,
+									 yyscanner);
+					$$ = (Node *)n;
+				}
 		;
 
 AlterDomainStmt:
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index b43765b..c6ef47c 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -68,7 +68,8 @@ extern Oid heap_create_with_catalog(const char *relname,
 						 Datum reloptions,
 						 bool use_user_acl,
 						 bool allow_system_table_mods,
-						 bool is_internal);
+						 bool is_internal,
+						 bool ifNotExists);
 
 extern void heap_create_init_fork(Relation rel);
 
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index e697275..ffeddfe 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -60,7 +60,8 @@ extern Oid index_create(Relation heapRelation,
 			 bool allow_system_table_mods,
 			 bool skip_build,
 			 bool concurrent,
-			 bool is_internal);
+			 bool is_internal,
+			 bool ifNotExists);
 
 extern void index_constraint_create(Relation heapRelation,
 						Oid indexRelationId,
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 51fef68..54c3f57 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1800,6 +1800,7 @@ typedef struct CreateEventTrigStmt
 	char	   *eventname;		/* event's identifier */
 	List	   *whenclause;		/* list of DefElems indicating filtering */
 	List	   *funcname;		/* qual. name of function to call */
+	bool		if_not_exists;	/* just do nothing if the event trigger already exists? */
 } CreateEventTrigStmt;
 
 /* ----------------------
@@ -1888,6 +1889,7 @@ typedef struct CreateSeqStmt
 	RangeVar   *sequence;		/* the sequence to create */
 	List	   *options;
 	Oid			ownerId;		/* ID of owner, or InvalidOid for default */
+	bool		if_not_exists;	/* skip error if a Sequence already exists */
 } CreateSeqStmt;
 
 typedef struct AlterSeqStmt
@@ -1910,6 +1912,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -1923,6 +1926,7 @@ typedef struct CreateDomainStmt
 	TypeName   *typeName;		/* the base type */
 	CollateClause *collClause;	/* untransformed COLLATE spec, if any */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
+	bool		if_not_exists;	/* just do nothing if domain already exists? */
 } CreateDomainStmt;
 
 /* ----------------------
@@ -2130,6 +2134,7 @@ typedef struct IndexStmt
 	bool		deferrable;		/* is the constraint DEFERRABLE? */
 	bool		initdeferred;	/* is the constraint INITIALLY DEFERRED? */
 	bool		concurrent;		/* should this be a concurrent index build? */
+	bool		if_not_exists;	/* just do nothing if index already exists? */
 } IndexStmt;
 
 /* ----------------------
@@ -2324,6 +2329,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2335,6 +2341,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2346,6 +2353,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2615,6 +2623,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 4e4df0c..6f2becf 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -581,6 +581,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -605,6 +609,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 78e7704..3a03df8 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -1,6 +1,12 @@
 --
 -- Test domains.
 --
+-- Test IF NOT EXISTS
+create domain domainifnotexists int4;
+create domain domainifnotexists int4;
+ERROR:  type "domainifnotexists" already exists
+create domain if not exists domainifnotexists int4;
+NOTICE:  type "domainifnotexists" already exists, skipping
 -- Test Comment / Drop
 create domain domaindroptest int4;
 comment on domain domaindroptest is 'About to drop this..';
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 656d47f..b3a6ad8 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -16,6 +16,14 @@ ERROR:  unrecognized event name "elephant_bootstrap"
 -- OK
 create event trigger regress_event_trigger on ddl_command_start
    execute procedure test_event_trigger();
+-- FAIL
+create event trigger regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+ERROR:  event trigger "regress_event_trigger" already exists
+-- FAIL, but skipp
+create event trigger if not exists regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+NOTICE:  event trigger "regress_event_trigger" already exists, skipping
 -- OK
 create event trigger regress_event_trigger_end on ddl_command_end
    execute procedure test_event_trigger();
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 87feb08..35aa7ee 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -91,6 +91,8 @@ SELECT nextval('serialTest2_f6_seq');
 
 -- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
+CREATE SEQUENCE IF NOT EXISTS sequence_test;
+NOTICE:  relation "sequence_test" already exists, skipping
 SELECT nextval('sequence_test'::text);
  nextval 
 ---------
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index d62f64f..f225ade 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -501,6 +501,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -521,6 +523,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 5af36af..f44f04c 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -2,6 +2,11 @@
 -- Test domains.
 --
 
+-- Test IF NOT EXISTS
+create domain domainifnotexists int4;
+create domain domainifnotexists int4;
+create domain if not exists domainifnotexists int4;
+
 -- Test Comment / Drop
 create domain domaindroptest int4;
 comment on domain domaindroptest is 'About to drop this..';
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 11d2ce5..190e1b3 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -18,6 +18,14 @@ create event trigger regress_event_trigger on elephant_bootstrap
 create event trigger regress_event_trigger on ddl_command_start
    execute procedure test_event_trigger();
 
+-- FAIL
+create event trigger regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+
+-- FAIL, but skipp
+create event trigger if not exists regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+
 -- OK
 create event trigger regress_event_trigger_end on ddl_command_end
    execute procedure test_event_trigger();
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index a32e049..f055382 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -59,6 +59,7 @@ SELECT nextval('serialTest2_f6_seq');
 
 -- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
+CREATE SEQUENCE IF NOT EXISTS sequence_test;
 
 SELECT nextval('sequence_test'::text);
 SELECT nextval('sequence_test'::regclass);
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#29Fabrízio de Royes Mello
fabrizio@timbira.com.br
In reply to: Fabrízio de Royes Mello (#28)
1 attachment(s)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 17-08-2013 18:10, Fabrízio de Royes Mello wrote:

On 26-07-2013 23:31, Abhijit Menon-Sen wrote:

At 2013-07-26 10:39:00 +0200, karlikt@gmail.com wrote:

Hello, as I can see there are more inconsistent places.

Right. This is what I was referring to in my original review. All of the
relevant sites (pre-patch) that currently do:

[...]

Hi all,

I'm sending, from the PGBR2013 (The Brazilian PostgreSQL Conference)
[1], the second part of this patch to cover another CREATE statements:

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]

Soon I'll sent the third and final part to finish this patch.

Attached some doc fixes.

Regards,

--
Fabrízio de Royes Mello Timbira - http://www.timbira.com.br/
PostgreSQL: Consultoria, Desenvolvimento, Suporte 24x7 e Treinamento

Attachments:

create_if_not_exists_v7.patchtext/x-patch; name=create_if_not_exists_v7.patchDownload
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..dcd809a 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> [ , ... ] ) (
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
@@ -31,7 +31,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceabl
 
 <phrase>or the old syntax</phrase>
 
-CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
+CREATE AGGREGATE [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable> (
     BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
     SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
@@ -177,6 +177,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an aggregate function with
+      the same argument types already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 29ea298..1c4c1df 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -18,15 +18,15 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH FUNCTION <replaceable>function_name</replaceable> (<replaceable>argument_type</replaceable> [, ...])
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITHOUT FUNCTION
     [ AS ASSIGNMENT | AS IMPLICIT ]
 
-CREATE CAST (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
+CREATE CAST [ IF NOT EXISTS ] (<replaceable>source_type</replaceable> AS <replaceable>target_type</replaceable>)
     WITH INOUT
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
@@ -171,6 +171,16 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Parameters</title>
 
    <variablelist>
+     <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a cast with the same
+        from and to type already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
     <varlistentry>
      <term><replaceable>source_type</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml
index c853576..f93d87e 100644
--- a/doc/src/sgml/ref/create_collation.sgml
+++ b/doc/src/sgml/ref/create_collation.sgml
@@ -18,12 +18,12 @@
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,16 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if an collation with the same
+      name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml
index 49db069..23b7611 100644
--- a/doc/src/sgml/ref/create_domain.sgml
+++ b/doc/src/sgml/ref/create_domain.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replaceable class="parameter">data_type</replaceable>
+CREATE DOMAIN [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> [ AS ] <replaceable class="parameter">data_type</replaceable>
     [ COLLATE <replaceable>collation</replaceable> ]
     [ DEFAULT <replaceable>expression</replaceable> ]
     [ <replaceable class="PARAMETER">constraint</replaceable> [ ... ] ]
@@ -71,6 +71,16 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if a domain with the same name
+        already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_event_trigger.sgml b/doc/src/sgml/ref/create_event_trigger.sgml
index ed66322..cc5969a 100644
--- a/doc/src/sgml/ref/create_event_trigger.sgml
+++ b/doc/src/sgml/ref/create_event_trigger.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
+CREATE EVENT TRIGGER [ IF NOT EXISTS ] <replaceable class="PARAMETER">name</replaceable>
   ON <replaceable class="PARAMETER">event</replaceable>
   [ WHEN <replaceable class="PARAMETER">filter_variable</replaceable> IN (filter_value [, ... ]) [ AND ... ] ]
   EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable>()
@@ -46,6 +46,16 @@ CREATE EVENT TRIGGER <replaceable class="PARAMETER">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a event trigger the
+      same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index dd33f06..80a6bf6 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE OPERATOR <replaceable>name</replaceable> (
+CREATE OPERATOR [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     PROCEDURE = <replaceable class="parameter">function_name</replaceable>
     [, LEFTARG = <replaceable class="parameter">left_type</replaceable> ] [, RIGHTARG = <replaceable class="parameter">right_type</replaceable> ]
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
@@ -117,6 +117,16 @@ CREATE OPERATOR <replaceable>name</replaceable> (
 
     <variablelist>
      <varlistentry>
+      <term><literal>IF NOT EXISTS</literal></term>
+      <listitem>
+       <para>
+        Do nothing (except issuing a notice) if an operator with the same
+        name already exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml
index 38d160d..982ffe3 100644
--- a/doc/src/sgml/ref/create_sequence.sgml
+++ b/doc/src/sgml/ref/create_sequence.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE [ TEMPORARY | TEMP ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
+CREATE [ TEMPORARY | TEMP ] [ IF NOT EXISTS ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
     [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ]
@@ -90,6 +90,16 @@ SELECT * FROM <replaceable>name</replaceable>;
    </varlistentry>
 
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a sequence with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
@@ -343,8 +353,8 @@ END;
     </listitem>
     <listitem>
      <para>
-      The <literal>OWNED BY</> clause is a <productname>PostgreSQL</>
-      extension.
+      The <literal>OWNED BY</> and <literal>IF NOT EXISTS</> clause
+      is a <productname>PostgreSQL</> extension.
      </para>
     </listitem>
    </itemizedlist></para>
diff --git a/doc/src/sgml/ref/create_tsconfig.sgml b/doc/src/sgml/ref/create_tsconfig.sgml
index c34d1c0..2cc7c1f 100644
--- a/doc/src/sgml/ref/create_tsconfig.sgml
+++ b/doc/src/sgml/ref/create_tsconfig.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH CONFIGURATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     PARSER = <replaceable class="parameter">parser_name</replaceable> |
     COPY = <replaceable class="parameter">source_config</replaceable>
 )
@@ -66,6 +66,16 @@ CREATE TEXT SEARCH CONFIGURATION <replaceable class="parameter">name</replaceabl
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search configuration
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsdictionary.sgml b/doc/src/sgml/ref/create_tsdictionary.sgml
index 2673bc5..4ffd408 100644
--- a/doc/src/sgml/ref/create_tsdictionary.sgml
+++ b/doc/src/sgml/ref/create_tsdictionary.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH DICTIONARY [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     TEMPLATE = <replaceable class="parameter">template</replaceable>
     [, <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">value</replaceable> [, ... ]]
 )
@@ -59,6 +59,16 @@ CREATE TEXT SEARCH DICTIONARY <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search dictionary
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tsparser.sgml b/doc/src/sgml/ref/create_tsparser.sgml
index 7643f08..1631af4 100644
--- a/doc/src/sgml/ref/create_tsparser.sgml
+++ b/doc/src/sgml/ref/create_tsparser.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH PARSER [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     START = <replaceable class="parameter">start_function</replaceable> ,
     GETTOKEN = <replaceable class="parameter">gettoken_function</replaceable> ,
     END = <replaceable class="parameter">end_function</replaceable> ,
@@ -64,6 +64,16 @@ CREATE TEXT SEARCH PARSER <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search parser
+      with the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_tstemplate.sgml b/doc/src/sgml/ref/create_tstemplate.sgml
index 532419c..ac65baf 100644
--- a/doc/src/sgml/ref/create_tstemplate.sgml
+++ b/doc/src/sgml/ref/create_tstemplate.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
+CREATE TEXT SEARCH TEMPLATE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     [ INIT = <replaceable class="parameter">init_function</replaceable> , ]
     LEXIZE = <replaceable class="parameter">lexize_function</replaceable>
 )
@@ -65,6 +65,16 @@ CREATE TEXT SEARCH TEMPLATE <replaceable class="parameter">name</replaceable> (
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a text search template with
+      the same name already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 606efee..0919da7 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -21,13 +21,13 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS
     ( [ <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ COLLATE <replaceable>collation</replaceable> ] [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS ENUM
     ( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> AS RANGE (
     SUBTYPE = <replaceable class="parameter">subtype</replaceable>
     [ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
     [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
@@ -35,7 +35,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
     [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable> (
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> (
     INPUT = <replaceable class="parameter">input_function</replaceable>,
     OUTPUT = <replaceable class="parameter">output_function</replaceable>
     [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
@@ -56,7 +56,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , COLLATABLE = <replaceable class="parameter">collatable</replaceable> ]
 )
 
-CREATE TYPE <replaceable class="parameter">name</replaceable>
+CREATE TYPE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -484,6 +484,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
 
   <variablelist>
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a type with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index cee72c1..aca9964 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -249,6 +249,7 @@ Boot_CreateStmt:
 													  (Datum) 0,
 													  false,
 													  true,
+													  false,
 													  false);
 						elog(DEBUG4, "relation created with OID %u", id);
 					}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 64ca312..57f7056 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -963,7 +963,8 @@ AddNewRelationType(const char *typeName,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists flag */
 }
 
 /* --------------------------------
@@ -1016,7 +1017,8 @@ heap_create_with_catalog(const char *relname,
 						 Datum reloptions,
 						 bool use_user_acl,
 						 bool allow_system_table_mods,
-						 bool is_internal)
+						 bool is_internal,
+						 bool ifNotExists)
 {
 	Relation	pg_class_desc;
 	Relation	new_rel_desc;
@@ -1041,9 +1043,20 @@ heap_create_with_catalog(const char *relname,
 	 */
 	existing_relid = get_relname_relid(relname, relnamespace);
 	if (existing_relid != InvalidOid)
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_TABLE),
+					 errmsg("relation \"%s\" already exists, skipping", relname)));
+			heap_close(pg_class_desc, RowExclusiveLock);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
 				 errmsg("relation \"%s\" already exists", relname)));
+	}
 
 	/*
 	 * Since we are going to create a rowtype as well, also check for
@@ -1219,7 +1232,8 @@ heap_create_with_catalog(const char *relname,
 				   -1,			/* typmod */
 				   0,			/* array dimensions for typBaseType */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
+				   InvalidOid,	/* rowtypes never have a collation */
+				   false);		/* if not exists */
 
 		pfree(relarrayname);
 	}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b73ee4f..6fd659d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -695,7 +695,8 @@ index_create(Relation heapRelation,
 			 bool allow_system_table_mods,
 			 bool skip_build,
 			 bool concurrent,
-			 bool is_internal)
+			 bool is_internal,
+			 bool ifNotExists)
 {
 	Oid			heapRelationId = RelationGetRelid(heapRelation);
 	Relation	pg_class;
@@ -771,10 +772,22 @@ index_create(Relation heapRelation,
 		elog(ERROR, "shared relations must be placed in pg_global tablespace");
 
 	if (get_relname_relid(indexRelationName, namespaceId))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_TABLE),
+					 errmsg("relation \"%s\" already exists, skipping",
+							indexRelationName)));
+			heap_close(pg_class, RowExclusiveLock);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
 				 errmsg("relation \"%s\" already exists",
 						indexRelationName)));
+	}
 
 	/*
 	 * construct tuple descriptor for index tuples
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 480c17c..fecc994 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,7 +51,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				bool aggIfNotExists)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -252,7 +253,11 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,		/* prorows */
+							  aggIfNotExists);	/* if not exists */
+
+	if (!OidIsValid(procOid))
+		return InvalidOid;
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 3c4fedb..47fcb4f 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -336,7 +336,8 @@ OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash)
+			   bool canHash,
+			   bool ifNotExists)
 {
 	Relation	pg_operator_desc;
 	HeapTuple	tup;
@@ -417,10 +418,22 @@ OperatorCreate(const char *operatorName,
 								   &operatorAlreadyDefined);
 
 	if (operatorAlreadyDefined)
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_FUNCTION),
+					 errmsg("operator %s already exists, skipping",
+							operatorName)));
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_FUNCTION),
 				 errmsg("operator %s already exists",
 						operatorName)));
+	}
 
 	/*
 	 * At this point, if operatorObjectId is not InvalidOid then we are
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 2a98ca9..fd3b655 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -88,7 +88,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				bool ifNotExists)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -388,10 +389,23 @@ ProcedureCreate(const char *procedureName,
 		bool		isnull;
 
 		if (!replace)
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_FUNCTION),
+						 errmsg("function \"%s\" already exists with same argument types, skipping",
+								procedureName)));
+				ReleaseSysCache(oldtup);
+				heap_close(rel, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_FUNCTION),
-			errmsg("function \"%s\" already exists with same argument types",
-				   procedureName)));
+					 errmsg("function \"%s\" already exists with same argument types",
+							procedureName)));
+		}
 		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
 						   procedureName);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 23ac3dd..03d8216 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -215,7 +215,8 @@ TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,		/* Array dimensions for baseType */
 		   bool typeNotNull,
-		   Oid typeCollation)
+		   Oid typeCollation,
+		   bool ifNotExists)
 {
 	Relation	pg_type_desc;
 	Oid			typeObjectId;
@@ -397,9 +398,21 @@ TypeCreate(Oid newTypeOid,
 		 * shell type, however.
 		 */
 		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				heap_close(pg_type_desc, RowExclusiveLock);
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 
 		/*
 		 * shell type must have been created by same owner
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 385d64d..441342e 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -228,7 +228,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
 										   reloptions,
 										   false,
 										   true,
-										   true);
+										   true,
+										   false);
 	Assert(toast_relid != InvalidOid);
 
 	/* make the toast relation visible, else heap_open will fail */
@@ -281,7 +282,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
 				 rel->rd_rel->reltablespace,
 				 collationObjectId, classObjectId, coloptions, (Datum) 0,
 				 true, false, false, false,
-				 true, false, false, true);
+				 true, false, false, true,
+				 false);
 
 	heap_close(toast_rel, NoLock);
 
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..9f128bd 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -48,7 +48,7 @@
  * "args" defines the input type(s).
  */
 Oid
-DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, bool ifNotExists)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
@@ -224,6 +224,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 						   transfuncName,		/* step function name */
 						   finalfuncName,		/* final function name */
 						   sortoperatorName,	/* sort operator name */
-						   transTypeId, /* transition data type */
-						   initval);	/* initial condition */
+						   transTypeId,	/* transition data type */
+						   initval,		/* initial condition */
+						   ifNotExists);	/* if not exists flag */
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 051b806..151dc6b 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -686,7 +686,8 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
 										  reloptions,
 										  false,
 										  true,
-										  true);
+										  true,
+										  false);
 	Assert(OIDNewHeap != InvalidOid);
 
 	ReleaseSysCache(tuple);
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 328e2a8..8e9a689 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -189,10 +189,22 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
 	 */
 	tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
 	if (HeapTupleIsValid(tuple))
+	{
+		if (stmt->if_not_exists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("event trigger \"%s\" already exists, skipping",
+							stmt->trigname)));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("event trigger \"%s\" already exists",
 						stmt->trigname)));
+	}
 
 	/* Find and validate the trigger function. */
 	funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0a9facf..488dba2 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -983,7 +983,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 						   parameterDefaults,
 						   PointerGetDatum(proconfig),
 						   procost,
-						   prorows);
+						   prorows,
+						   false);
 }
 
 
@@ -1498,8 +1499,6 @@ CreateCast(CreateCastStmt *stmt)
 			break;
 	}
 
-	relation = heap_open(CastRelationId, RowExclusiveLock);
-
 	/*
 	 * Check for duplicate.  This is just to give a friendly error message,
 	 * the unique index would catch it anyway (so no need to sweat about race
@@ -1509,11 +1508,27 @@ CreateCast(CreateCastStmt *stmt)
 							ObjectIdGetDatum(sourcetypeid),
 							ObjectIdGetDatum(targettypeid));
 	if (HeapTupleIsValid(tuple))
+	{
+		/* skip if already exists */
+		if (stmt->if_not_exists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("cast from type %s to type %s already exists, skipping",
+							format_type_be(sourcetypeid),
+							format_type_be(targettypeid))));
+			ReleaseSysCache(tuple);
+			return InvalidOid;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("cast from type %s to type %s already exists",
 						format_type_be(sourcetypeid),
 						format_type_be(targettypeid))));
+	}
+
+	relation = heap_open(CastRelationId, RowExclusiveLock);
 
 	/* ready to go */
 	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 902daa0..e20bd0d 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -601,7 +601,14 @@ DefineIndex(IndexStmt *stmt,
 					 stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
 					 allowSystemTableMods,
 					 skip_build || stmt->concurrent,
-					 stmt->concurrent, !check_rights);
+					 stmt->concurrent, !check_rights,
+					 stmt->if_not_exists);
+
+	if (!OidIsValid(indexRelationId))
+	{
+		heap_close(rel, NoLock);
+		return indexRelationId;
+	}
 
 	/* Add any requested comment */
 	if (stmt->idxcomment != NULL)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 4692b08..c8d3363 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -60,7 +60,7 @@
  * 'parameters' is a list of DefElem
  */
 Oid
-DefineOperator(List *names, List *parameters)
+DefineOperator(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *oprName;
 	Oid			oprNamespace;
@@ -306,7 +306,8 @@ DefineOperator(List *names, List *parameters)
 					   restrictionOid,	/* optional restrict. sel. procedure */
 					   joinOid, /* optional join sel. procedure name */
 					   canMerge,	/* operator merges */
-					   canHash);	/* operator hashes */
+					   canHash,		/* operator hashes */
+					   ifNotExists);	/* if not exists flag */
 }
 
 /*
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index b7be1f7..28f22fc 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -141,7 +141,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 		}
 
 		/*
@@ -178,7 +179,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											false);
 			}
 		}
 		else
@@ -218,7 +220,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 false);
 			}
 		}
 		else
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index ddfaf3b..5e89b39 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -213,9 +213,13 @@ DefineSequence(CreateSeqStmt *seq)
 	stmt->options = NIL;
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
-	stmt->if_not_exists = false;
+	stmt->if_not_exists = seq->if_not_exists;
 
 	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
+
+	if (seq->if_not_exists && !OidIsValid(seqoid))
+		return InvalidOid;
+
 	Assert(seqoid != InvalidOid);
 
 	rel = heap_open(seqoid, AccessExclusiveLock);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index adc74dd..e4099bd 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -643,7 +643,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 										  reloptions,
 										  true,
 										  allowSystemTableMods,
-										  false);
+										  false,
+										  stmt->if_not_exists);
+
+	if (!OidIsValid(relationId))
+		return relationId;
 
 	/* Store inheritance information for new rel. */
 	StoreCatalogInheritance(relationId, inheritOids);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 61ebc2e..4885ed8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -168,7 +168,7 @@ makeParserDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH PARSER
  */
 Oid
-DefineTSParser(List *names, List *parameters)
+DefineTSParser(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *prsname;
 	ListCell   *pl;
@@ -188,6 +188,31 @@ DefineTSParser(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
 
+	/* Check if text search parser already exists */
+	prsOid = GetSysCacheOid2(TSPARSERNAMENSP,
+							 CStringGetDatum(prsname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(prsOid))
+	{
+		/* skip if already exists */
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search parser \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							prsname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search parser \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						prsname)));
+	}
+
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
 	memset(nulls, false, sizeof(nulls));
@@ -398,7 +423,7 @@ verify_dictoptions(Oid tmplId, List *dictoptions)
  * CREATE TEXT SEARCH DICTIONARY
  */
 Oid
-DefineTSDictionary(List *names, List *parameters)
+DefineTSDictionary(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	dictRel;
@@ -412,15 +437,43 @@ DefineTSDictionary(List *names, List *parameters)
 	Oid			namespaceoid;
 	AclResult	aclresult;
 	char	   *dictname;
+	char	   *dictnamespace;
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
 
+	/* Get namespace name */
+	dictnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   dictnamespace);
+
+	/* Check if text search dictionary already exists */
+	dictOid = GetSysCacheOid2(TSDICTNAMENSP,
+							  CStringGetDatum(dictname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(dictOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search dictionary \"%s\".\"%s\" already exists, skipping",
+							dictnamespace,
+							dictname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search dictionary \"%s\".\"%s\" already exists",
+						dictnamespace,
+						dictname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -716,7 +769,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
  * CREATE TEXT SEARCH TEMPLATE
  */
 Oid
-DefineTSTemplate(List *names, List *parameters)
+DefineTSTemplate(List *names, List *parameters, bool ifNotExists)
 {
 	ListCell   *pl;
 	Relation	tmplRel;
@@ -737,6 +790,30 @@ DefineTSTemplate(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
 
+	/* Check if text search template already exists */
+	tmplOid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+							  CStringGetDatum(tmplname),
+							  ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(tmplOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search template \"%s\".\"%s\" already exists, skipping",
+							get_namespace_name(namespaceoid),
+							tmplname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search template \"%s\".\"%s\" already exists",
+						get_namespace_name(namespaceoid),
+						tmplname)));
+	}
+
 	for (i = 0; i < Natts_pg_ts_template; i++)
 	{
 		nulls[i] = false;
@@ -946,7 +1023,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
  * CREATE TEXT SEARCH CONFIGURATION
  */
 Oid
-DefineTSConfiguration(List *names, List *parameters)
+DefineTSConfiguration(List *names, List *parameters, bool ifNotExists)
 {
 	Relation	cfgRel;
 	Relation	mapRel = NULL;
@@ -956,6 +1033,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	AclResult	aclresult;
 	Oid			namespaceoid;
 	char	   *cfgname;
+	char	   *cfgnamespace;
 	NameData	cname;
 	Oid			sourceOid = InvalidOid;
 	Oid			prsOid = InvalidOid;
@@ -965,11 +1043,38 @@ DefineTSConfiguration(List *names, List *parameters)
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
 
+	/* Get namespace name */
+	cfgnamespace = get_namespace_name(namespaceoid);
+
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
-					   get_namespace_name(namespaceoid));
+					   cfgnamespace);
+
+	/* Check if text search configuration already exists */
+	cfgOid = GetSysCacheOid2(TSCONFIGNAMENSP,
+							 CStringGetDatum(cfgname),
+							 ObjectIdGetDatum(namespaceoid));
+
+	if (OidIsValid(cfgOid))
+	{
+		if (ifNotExists)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("text search configuration \"%s\".\"%s\" already exists, skipping",
+							cfgnamespace,
+							cfgname)));
+			return InvalidOid;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("text search configuration \"%s\".\"%s\" already exists",
+						cfgnamespace,
+						cfgname)));
+	}
 
 	/*
 	 * loop over the definition list and extract the information we need.
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..2a00dfb 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -114,7 +114,7 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
  *		Registers a new base type.
  */
 Oid
-DefineType(List *names, List *parameters)
+DefineType(List *names, List *parameters, bool ifNotExists)
 {
 	char	   *typeName;
 	Oid			typeNamespace;
@@ -233,9 +233,20 @@ DefineType(List *names, List *parameters)
 	{
 		/* Complain if dummy CREATE TYPE and entry already exists */
 		if (parameters == NIL)
+		{
+			/* skip if already exists */
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/* Extract the parameters from the parameter list */
@@ -585,7 +596,11 @@ DefineType(List *names, List *parameters)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array Dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   collation);	/* type's collation */
+				   collation,	/* type's collation */
+				   ifNotExists);	/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/*
 	 * Create the array type that goes with it.
@@ -621,11 +636,12 @@ DefineType(List *names, List *parameters)
 						NULL,	/* binary default isn't sent either */
 						false,	/* never passed by value */
 						alignment,		/* see above */
-						'x',	/* ARRAY is always toastable */
-						-1,		/* typMod (Domains only) */
-						0,		/* Array dimensions of typbasetype */
-						false,	/* Type NOT NULL */
-						collation);		/* type's collation */
+						'x',				/* ARRAY is always toastable */
+						-1,				/* typMod (Domains only) */
+						0,				/* Array dimensions of typbasetype */
+						false,			/* Type NOT NULL */
+						collation,		/* type's collation */
+						ifNotExists);	/* if not exists flag */
 
 	pfree(array_type);
 
@@ -733,9 +749,19 @@ DefineDomain(CreateDomainStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", domainName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", domainName)));
+		}
 	}
 
 	/*
@@ -1011,7 +1037,14 @@ DefineDomain(CreateDomainStmt *stmt)
 				   basetypeMod, /* typeMod value */
 				   typNDims,	/* Array dimensions for base type */
 				   typNotNull,	/* Type NOT NULL */
-				   domaincoll); /* type's collation */
+				   domaincoll,	/* type's collation */
+				   stmt->if_not_exists);	/* if not exists flag */
+
+	if (!OidIsValid(domainoid))
+	{
+		ReleaseSysCache(typeTup);
+		return domainoid;
+	}
 
 	/*
 	 * Process constraints which refer to the domain ID returned by TypeCreate
@@ -1084,9 +1117,20 @@ DefineEnum(CreateEnumStmt *stmt)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", enumName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", enumName)));
+
+		}
 	}
 
 	enumArrayOid = AssignTypeArrayOid();
@@ -1123,7 +1167,11 @@ DefineEnum(CreateEnumStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation */
+				   InvalidOid,	/* type's collation */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(enumTypeOid))
+		return enumTypeOid;
 
 	/* Enter the enum's values into pg_enum */
 	EnumValuesCreate(enumTypeOid, stmt->vals);
@@ -1163,7 +1211,8 @@ DefineEnum(CreateEnumStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* type's collation */
+			   InvalidOid,		/* type's collation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(enumArrayName);
 
@@ -1302,9 +1351,19 @@ DefineRange(CreateRangeStmt *stmt)
 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
 			typoid = InvalidOid;
 		else
+		{
+			if (stmt->if_not_exists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", typeName)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", typeName)));
+		}
 	}
 
 	/*
@@ -1457,7 +1516,11 @@ DefineRange(CreateRangeStmt *stmt)
 				   -1,			/* typMod (Domains only) */
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
-				   InvalidOid); /* type's collation (ranges never have one) */
+				   InvalidOid,	/* type's collation (ranges never have one) */
+				   stmt->if_not_exists);		/* if not exists flag */
+
+	if (!OidIsValid(typoid))
+		return typoid;
 
 	/* Create the entry in pg_range */
 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1498,7 +1561,8 @@ DefineRange(CreateRangeStmt *stmt)
 			   -1,				/* typMod (Domains only) */
 			   0,				/* Array dimensions of typbasetype */
 			   false,			/* Type NOT NULL */
-			   InvalidOid);		/* typcollation */
+			   InvalidOid,		/* typcollation */
+			   stmt->if_not_exists);			/* if not exists flag */
 
 	pfree(rangeArrayName);
 
@@ -1569,7 +1633,8 @@ makeRangeConstructors(const char *name, Oid namespace,
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0,	/* prorows */
+								  false);	/* if not exists */
 
 		/*
 		 * Make the constructors internally-dependent on the range type so
@@ -2018,7 +2083,7 @@ AssignTypeArrayOid(void)
  *-------------------------------------------------------------------
  */
 Oid
-DefineCompositeType(RangeVar *typevar, List *coldeflist)
+DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
 	Oid			old_type_oid;
@@ -2054,9 +2119,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	if (OidIsValid(old_type_oid))
 	{
 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
+		{
+			if (ifNotExists)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_DUPLICATE_OBJECT),
+						 errmsg("type \"%s\" already exists, skipping", createStmt->relation->relname)));
+				return InvalidOid;
+			}
+
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
+		}
 	}
 
 	/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 788907e..211d367 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2783,6 +2783,7 @@ _copyDefineStmt(const DefineStmt *from)
 	COPY_NODE_FIELD(defnames);
 	COPY_NODE_FIELD(args);
 	COPY_NODE_FIELD(definition);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -2876,6 +2877,7 @@ _copyIndexStmt(const IndexStmt *from)
 	COPY_SCALAR_FIELD(deferrable);
 	COPY_SCALAR_FIELD(initdeferred);
 	COPY_SCALAR_FIELD(concurrent);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3042,6 +3044,7 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3053,6 +3056,7 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3064,6 +3068,7 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3116,6 +3121,7 @@ _copyCreateDomainStmt(const CreateDomainStmt *from)
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(collClause);
 	COPY_NODE_FIELD(constraints);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
@@ -3680,6 +3686,7 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 	COPY_NODE_FIELD(func);
 	COPY_SCALAR_FIELD(context);
 	COPY_SCALAR_FIELD(inout);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 496e31d..ad42871 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1124,6 +1124,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 	COMPARE_NODE_FIELD(defnames);
 	COMPARE_NODE_FIELD(args);
 	COMPARE_NODE_FIELD(definition);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1345,6 +1346,7 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1354,6 +1356,7 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1363,6 +1366,7 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1407,6 +1411,7 @@ _equalCreateDomainStmt(const CreateDomainStmt *a, const CreateDomainStmt *b)
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(collClause);
 	COMPARE_NODE_FIELD(constraints);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1542,6 +1547,7 @@ _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(ownerId);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
@@ -1883,6 +1889,7 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 	COMPARE_NODE_FIELD(func);
 	COMPARE_SCALAR_FIELD(context);
 	COMPARE_SCALAR_FIELD(inout);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 22e82ba..fc4b671 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3328,6 +3328,17 @@ CreateSeqStmt:
 					n->sequence = $4;
 					n->options = $5;
 					n->ownerId = InvalidOid;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList
+				{
+					CreateSeqStmt *n = makeNode(CreateSeqStmt);
+					$7->relpersistence = $2;
+					n->sequence = $7;
+					n->options = $8;
+					n->ownerId = InvalidOid;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4501,6 +4512,18 @@ CreateEventTrigStmt:
 					n->eventname = $6;
 					n->whenclause = NULL;
 					n->funcname = $9;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+		  | CREATE EVENT TRIGGER IF_P NOT EXISTS name ON ColLabel
+			EXECUTE PROCEDURE func_name '(' ')'
+				{
+					CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
+					n->trigname = $7;
+					n->eventname = $9;
+					n->whenclause = NULL;
+					n->funcname = $12;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		  | CREATE EVENT TRIGGER name ON ColLabel
@@ -4512,6 +4535,19 @@ CreateEventTrigStmt:
 					n->eventname = $6;
 					n->whenclause = $8;
 					n->funcname = $11;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+		  | CREATE EVENT TRIGGER IF_P NOT EXISTS name ON ColLabel
+			WHEN event_trigger_when_list
+			EXECUTE PROCEDURE func_name '(' ')'
+				{
+					CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
+					n->trigname = $7;
+					n->eventname = $9;
+					n->whenclause = $11;
+					n->funcname = $14;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4612,6 +4648,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = $4;
 					n->definition = $5;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name aggr_args definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = $7;
+					n->definition = $8;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE AGGREGATE func_name old_aggr_definition
@@ -4623,6 +4671,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE AGGREGATE IF_P NOT EXISTS func_name old_aggr_definition
+				{
+					/* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_AGGREGATE;
+					n->oldstyle = true;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE OPERATOR any_operator definition
@@ -4633,6 +4694,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OPERATOR IF_P NOT EXISTS any_operator definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_OPERATOR;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name definition
@@ -4643,6 +4716,18 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name
@@ -4654,6 +4739,19 @@ DefineStmt:
 					n->defnames = $3;
 					n->args = NIL;
 					n->definition = NIL;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name
+				{
+					/* Shell type (identified by lack of definition) */
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TYPE;
+					n->oldstyle = false;
+					n->defnames = $6;
+					n->args = NIL;
+					n->definition = NIL;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')'
@@ -4663,6 +4761,17 @@ DefineStmt:
 					/* can't use qualified_name, sigh */
 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->coldeflist = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS '(' OptTableFuncElementList ')'
+				{
+					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
+
+					/* can't use qualified_name, sigh */
+					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
+					n->coldeflist = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')'
@@ -4670,6 +4779,15 @@ DefineStmt:
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
 					n->typeName = $3;
 					n->vals = $7;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS ENUM_P '(' opt_enum_val_list ')'
+				{
+					CreateEnumStmt *n = makeNode(CreateEnumStmt);
+					n->typeName = $6;
+					n->vals = $10;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TYPE_P any_name AS RANGE definition
@@ -4677,6 +4795,15 @@ DefineStmt:
 					CreateRangeStmt *n = makeNode(CreateRangeStmt);
 					n->typeName = $3;
 					n->params	= $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TYPE_P IF_P NOT EXISTS any_name AS RANGE definition
+				{
+					CreateRangeStmt *n = makeNode(CreateRangeStmt);
+					n->typeName = $6;
+					n->params	= $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH PARSER any_name definition
@@ -4686,6 +4813,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH PARSER IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSPARSER;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
@@ -4695,6 +4833,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH DICTIONARY IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSDICTIONARY;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
@@ -4704,6 +4853,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH TEMPLATE IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSTEMPLATE;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE TEXT_P SEARCH CONFIGURATION any_name definition
@@ -4713,6 +4873,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $5;
 					n->definition = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE TEXT_P SEARCH CONFIGURATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_TSCONFIGURATION;
+					n->args = NIL;
+					n->defnames = $8;
+					n->definition = $9;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name definition
@@ -4722,6 +4893,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name definition
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = $7;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 			| CREATE COLLATION any_name FROM any_name
@@ -4731,6 +4913,17 @@ DefineStmt:
 					n->args = NIL;
 					n->defnames = $3;
 					n->definition = list_make1(makeDefElem("from", (Node *) $5));
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+				{
+					DefineStmt *n = makeNode(DefineStmt);
+					n->kind = OBJECT_COLLATION;
+					n->args = NIL;
+					n->defnames = $6;
+					n->definition = list_make1(makeDefElem("from", (Node *) $8));
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
@@ -4832,8 +5025,8 @@ AlterEnumStmt:
 			}
 		 ;
 
-opt_if_not_exists: IF_P NOT EXISTS              { $$ = true; }
-         | /* empty */                          { $$ = false; }
+opt_if_not_exists: IF_P NOT EXISTS              { $$ = TRUE; }
+         | /* empty */                          { $$ = FALSE; }
          ;
 
 
@@ -6106,6 +6299,7 @@ IndexStmt:	CREATE opt_unique INDEX opt_concurrently opt_index_name
 					n->isconstraint = false;
 					n->deferrable = false;
 					n->initdeferred = false;
+					n->if_not_exists = false;
 					$$ = (Node *)n;
 				}
 		;
@@ -6701,37 +6895,40 @@ dostmt_opt_item:
  *
  *****************************************************************************/
 
-CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+CreateCastStmt: CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH FUNCTION function_with_argtypes cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
-					n->func = $10;
-					n->context = (CoercionContext) $11;
+					n->sourcetype = $5;
+					n->targettype = $7;
+					n->func = $11;
+					n->context = (CoercionContext) $12;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITHOUT FUNCTION cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = false;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
-			| CREATE CAST '(' Typename AS Typename ')'
+			| CREATE CAST opt_if_not_exists '(' Typename AS Typename ')'
 					WITH INOUT cast_context
 				{
 					CreateCastStmt *n = makeNode(CreateCastStmt);
-					n->sourcetype = $4;
-					n->targettype = $6;
+					n->sourcetype = $5;
+					n->targettype = $7;
 					n->func = NULL;
-					n->context = (CoercionContext) $10;
+					n->context = (CoercionContext) $11;
 					n->inout = true;
+					n->if_not_exists = $3;
 					$$ = (Node *)n;
 				}
 		;
@@ -8252,10 +8449,21 @@ CreateDomainStmt:
 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
 					n->domainname = $3;
 					n->typeName = $5;
+					n->if_not_exists = false;
 					SplitColQualList($6, &n->constraints, &n->collClause,
 									 yyscanner);
 					$$ = (Node *)n;
 				}
+			| CREATE DOMAIN_P IF_P NOT EXISTS any_name opt_as Typename ColQualList
+				{
+					CreateDomainStmt *n = makeNode(CreateDomainStmt);
+					n->domainname = $6;
+					n->typeName = $8;
+					n->if_not_exists = true;
+					SplitColQualList($9, &n->constraints, &n->collClause,
+									 yyscanner);
+					$$ = (Node *)n;
+				}
 		;
 
 AlterDomainStmt:
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c940897..d33f67e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1103,34 +1103,41 @@ ProcessUtilitySlow(Node *parsetree,
 					{
 						case OBJECT_AGGREGATE:
 							DefineAggregate(stmt->defnames, stmt->args,
-											stmt->oldstyle, stmt->definition);
+											stmt->oldstyle, stmt->definition,
+											stmt->if_not_exists);
 							break;
 						case OBJECT_OPERATOR:
 							Assert(stmt->args == NIL);
-							DefineOperator(stmt->defnames, stmt->definition);
+							DefineOperator(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TYPE:
 							Assert(stmt->args == NIL);
-							DefineType(stmt->defnames, stmt->definition);
+							DefineType(stmt->defnames, stmt->definition,
+									   stmt->if_not_exists);
 							break;
 						case OBJECT_TSPARSER:
 							Assert(stmt->args == NIL);
-							DefineTSParser(stmt->defnames, stmt->definition);
+							DefineTSParser(stmt->defnames, stmt->definition,
+										   stmt->if_not_exists);
 							break;
 						case OBJECT_TSDICTIONARY:
 							Assert(stmt->args == NIL);
 							DefineTSDictionary(stmt->defnames,
-											   stmt->definition);
+											   stmt->definition,
+											   stmt->if_not_exists);
 							break;
 						case OBJECT_TSTEMPLATE:
 							Assert(stmt->args == NIL);
 							DefineTSTemplate(stmt->defnames,
-											 stmt->definition);
+											 stmt->definition,
+											 stmt->if_not_exists);
 							break;
 						case OBJECT_TSCONFIGURATION:
 							Assert(stmt->args == NIL);
 							DefineTSConfiguration(stmt->defnames,
-												  stmt->definition);
+												  stmt->definition,
+												  stmt->if_not_exists);
 							break;
 						case OBJECT_COLLATION:
 							Assert(stmt->args == NIL);
@@ -1211,7 +1218,7 @@ ProcessUtilitySlow(Node *parsetree,
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-					DefineCompositeType(stmt->typevar, stmt->coldeflist);
+					DefineCompositeType(stmt->typevar, stmt->coldeflist, stmt->if_not_exists);
 				}
 				break;
 
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index b43765b..c6ef47c 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -68,7 +68,8 @@ extern Oid heap_create_with_catalog(const char *relname,
 						 Datum reloptions,
 						 bool use_user_acl,
 						 bool allow_system_table_mods,
-						 bool is_internal);
+						 bool is_internal,
+						 bool ifNotExists);
 
 extern void heap_create_init_fork(Relation rel);
 
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index e697275..ffeddfe 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -60,7 +60,8 @@ extern Oid index_create(Relation heapRelation,
 			 bool allow_system_table_mods,
 			 bool skip_build,
 			 bool concurrent,
-			 bool is_internal);
+			 bool is_internal,
+			 bool ifNotExists);
 
 extern void index_constraint_create(Relation heapRelation,
 						Oid indexRelationId,
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65c8616 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -246,6 +246,7 @@ extern Oid AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				bool aggIfNotExists);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..18f3897 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1752,6 +1752,7 @@ extern Oid OperatorCreate(const char *operatorName,
 			   Oid restrictionId,
 			   Oid joinId,
 			   bool canMerge,
-			   bool canHash);
+			   bool canHash,
+			   bool ifNotExists);
 
 #endif   /* PG_OPERATOR_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 3b04301..d920c0b 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -39,7 +39,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				bool ifNotExists);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h
index b12d58a..e21a817 100644
--- a/src/include/catalog/pg_type_fn.h
+++ b/src/include/catalog/pg_type_fn.h
@@ -51,7 +51,8 @@ extern Oid TypeCreate(Oid newTypeOid,
 		   int32 typeMod,
 		   int32 typNDims,
 		   bool typeNotNull,
-		   Oid typeCollation);
+		   Oid typeCollation,
+		   bool ifNotExists);
 
 extern void GenerateTypeDependencies(Oid typeNamespace,
 						 Oid typeObjectId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..34baf01 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -55,12 +55,12 @@ extern void ExecuteDoStmt(DoStmt *stmt);
 extern Oid	get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
 
 /* commands/operatorcmds.c */
-extern Oid	DefineOperator(List *names, List *parameters);
+extern Oid DefineOperator(List *names, List *parameters, bool ifNotExists);
 extern void RemoveOperatorById(Oid operOid);
 
 /* commands/aggregatecmds.c */
 extern Oid DefineAggregate(List *name, List *args, bool oldstyle,
-				List *parameters);
+				List *parameters, bool ifNotExists);
 
 /* commands/opclasscmds.c */
 extern Oid	DefineOpClass(CreateOpClassStmt *stmt);
@@ -79,17 +79,17 @@ extern Oid	get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid	get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 
 /* commands/tsearchcmds.c */
-extern Oid	DefineTSParser(List *names, List *parameters);
+extern Oid DefineTSParser(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSParserById(Oid prsId);
 
-extern Oid	DefineTSDictionary(List *names, List *parameters);
+extern Oid DefineTSDictionary(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSDictionaryById(Oid dictId);
 extern Oid	AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 
-extern Oid	DefineTSTemplate(List *names, List *parameters);
+extern Oid DefineTSTemplate(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSTemplateById(Oid tmplId);
 
-extern Oid	DefineTSConfiguration(List *names, List *parameters);
+extern Oid DefineTSConfiguration(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern Oid	AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
 
diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h
index f45fde7..dbd4e32 100644
--- a/src/include/commands/typecmds.h
+++ b/src/include/commands/typecmds.h
@@ -21,13 +21,13 @@
 
 #define DEFAULT_TYPDELIM		','
 
-extern Oid	DefineType(List *names, List *parameters);
+extern Oid DefineType(List *names, List *parameters, bool ifNotExists);
 extern void RemoveTypeById(Oid typeOid);
 extern Oid	DefineDomain(CreateDomainStmt *stmt);
 extern Oid	DefineEnum(CreateEnumStmt *stmt);
 extern Oid	DefineRange(CreateRangeStmt *stmt);
 extern Oid	AlterEnum(AlterEnumStmt *stmt, bool isTopLevel);
-extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist);
+extern Oid	DefineCompositeType(RangeVar *typevar, List *coldeflist, bool ifNotExists);
 extern Oid	AssignTypeArrayOid(void);
 
 extern Oid	AlterDomainDefault(List *names, Node *defaultRaw);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 51fef68..54c3f57 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1800,6 +1800,7 @@ typedef struct CreateEventTrigStmt
 	char	   *eventname;		/* event's identifier */
 	List	   *whenclause;		/* list of DefElems indicating filtering */
 	List	   *funcname;		/* qual. name of function to call */
+	bool		if_not_exists;	/* just do nothing if the event trigger already exists? */
 } CreateEventTrigStmt;
 
 /* ----------------------
@@ -1888,6 +1889,7 @@ typedef struct CreateSeqStmt
 	RangeVar   *sequence;		/* the sequence to create */
 	List	   *options;
 	Oid			ownerId;		/* ID of owner, or InvalidOid for default */
+	bool		if_not_exists;	/* skip error if a Sequence already exists */
 } CreateSeqStmt;
 
 typedef struct AlterSeqStmt
@@ -1910,6 +1912,7 @@ typedef struct DefineStmt
 	List	   *defnames;		/* qualified name (list of Value strings) */
 	List	   *args;			/* a list of TypeName (if needed) */
 	List	   *definition;		/* a list of DefElem */
+	bool		if_not_exists;	/* just do nothing if {aggregate|operator|type} already exists? */
 } DefineStmt;
 
 /* ----------------------
@@ -1923,6 +1926,7 @@ typedef struct CreateDomainStmt
 	TypeName   *typeName;		/* the base type */
 	CollateClause *collClause;	/* untransformed COLLATE spec, if any */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
+	bool		if_not_exists;	/* just do nothing if domain already exists? */
 } CreateDomainStmt;
 
 /* ----------------------
@@ -2130,6 +2134,7 @@ typedef struct IndexStmt
 	bool		deferrable;		/* is the constraint DEFERRABLE? */
 	bool		initdeferred;	/* is the constraint INITIALLY DEFERRED? */
 	bool		concurrent;		/* should this be a concurrent index build? */
+	bool		if_not_exists;	/* just do nothing if index already exists? */
 } IndexStmt;
 
 /* ----------------------
@@ -2324,6 +2329,7 @@ typedef struct CompositeTypeStmt
 	NodeTag		type;
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CompositeTypeStmt;
 
 /* ----------------------
@@ -2335,6 +2341,7 @@ typedef struct CreateEnumStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateEnumStmt;
 
 /* ----------------------
@@ -2346,6 +2353,7 @@ typedef struct CreateRangeStmt
 	NodeTag		type;
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
+	bool		if_not_exists;	/* just do nothing if type already exists? */
 } CreateRangeStmt;
 
 /* ----------------------
@@ -2615,6 +2623,7 @@ typedef struct CreateCastStmt
 	FuncWithArgs *func;
 	CoercionContext context;
 	bool		inout;
+	bool		if_not_exists;	/* just do nothing if cast already exists? */
 } CreateCastStmt;
 
 /* ----------------------
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 4e4df0c..6f2becf 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -581,6 +581,10 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+ERROR:  text search template "alt_nsp1"."alt_ts_temp1" already exists
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
+NOTICE:  text search template "alt_nsp1"."alt_ts_temp1" already exists, skipping
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
 ERROR:  text search template "alt_ts_temp2" already exists in schema "alt_nsp1"
@@ -605,6 +609,12 @@ SELECT nspname, tmplname
 --
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ERROR:  text search parser "alt_nsp1"."alt_ts_prs1" already exists
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+NOTICE:  text search parser "alt_nsp1"."alt_ts_prs1" already exists, skipping
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 ALTER TEXT SEARCH PARSER alt_ts_prs1 RENAME TO alt_ts_prs2; -- failed (name conflict)
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index ad14594..e294d06 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -12,6 +12,19 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 ERROR:  aggregate newavg_wrong(integer) does not exist
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+ERROR:  function "newavg" already exists with same argument types
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+NOTICE:  function "newavg" already exists with same argument types, skipping
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index 56cd86e..1c3e6f0 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -29,6 +29,10 @@ LINE 1: SELECT casttestfunc('foo'::text);
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 ERROR:  function casttestfunc(text) does not exist
 LINE 1: SELECT casttestfunc('foo'::text);
@@ -43,6 +47,10 @@ SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+ERROR:  cast from type text to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+NOTICE:  cast from type text to type casttesttype already exists, skipping
 SELECT casttestfunc('foo'::text); -- Should work now
  casttestfunc 
 --------------
@@ -55,6 +63,10 @@ ERROR:  cannot cast type integer to casttesttype
 LINE 1: SELECT 1234::int4::casttesttype;
                          ^
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
@@ -66,6 +78,10 @@ DROP CAST (int4 AS casttesttype);
 CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+ERROR:  cast from type integer to type casttesttype already exists
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+NOTICE:  cast from type integer to type casttesttype already exists, skipping
 SELECT 1234::int4::casttesttype; -- Should work now
  casttesttype 
 --------------
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 2e6c764..3e5a2f7 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -7,6 +7,20 @@ CREATE OPERATOR ## (
    procedure = path_inter,
    commutator = ##
 );
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+ERROR:  operator ## already exists
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+NOTICE:  operator ## already exists, skipping
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 6dfe916..666a7c1 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -14,6 +14,24 @@ CREATE TYPE widget (
    typmod_out = numerictypmodout,
    alignment = double
 );
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+ERROR:  type "widget" already exists
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+NOTICE:  type "widget" already exists, skipping
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -26,6 +44,8 @@ CREATE TYPE city_budget (
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
 ERROR:  type "shell" already exists
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
+NOTICE:  type "shell" already exists, skipping
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 ERROR:  type "shell" does not exist
@@ -83,6 +103,10 @@ SELECT * FROM default_test;
 
 -- Test stand-alone composite type
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+ERROR:  type "default_test_row" already exists
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+NOTICE:  type "default_test_row" already exists, skipping
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 78e7704..3a03df8 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -1,6 +1,12 @@
 --
 -- Test domains.
 --
+-- Test IF NOT EXISTS
+create domain domainifnotexists int4;
+create domain domainifnotexists int4;
+ERROR:  type "domainifnotexists" already exists
+create domain if not exists domainifnotexists int4;
+NOTICE:  type "domainifnotexists" already exists, skipping
 -- Test Comment / Drop
 create domain domaindroptest int4;
 comment on domain domaindroptest is 'About to drop this..';
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 3682642..b95e6a5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -2,6 +2,10 @@
 -- Enum tests
 --
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+ERROR:  type "rainbow" already exists
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+NOTICE:  type "rainbow" already exists, skipping
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 656d47f..b3a6ad8 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -16,6 +16,14 @@ ERROR:  unrecognized event name "elephant_bootstrap"
 -- OK
 create event trigger regress_event_trigger on ddl_command_start
    execute procedure test_event_trigger();
+-- FAIL
+create event trigger regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+ERROR:  event trigger "regress_event_trigger" already exists
+-- FAIL, but skipp
+create event trigger if not exists regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+NOTICE:  event trigger "regress_event_trigger" already exists, skipping
 -- OK
 create event trigger regress_event_trigger_end on ddl_command_end
    execute procedure test_event_trigger();
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..7397498 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1,5 +1,9 @@
 -- Tests for range data types.
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+ERROR:  type "textrange" already exists
+create type if not exists textrange as range (subtype=text, collation="C");
+NOTICE:  type "textrange" already exists, skipping
 --
 -- test input parser
 --
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 87feb08..35aa7ee 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -91,6 +91,8 @@ SELECT nextval('serialTest2_f6_seq');
 
 -- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
+CREATE SEQUENCE IF NOT EXISTS sequence_test;
+NOTICE:  relation "sequence_test" already exists, skipping
 SELECT nextval('sequence_test'::text);
  nextval 
 ---------
diff --git a/src/test/regress/expected/tsdicts.out b/src/test/regress/expected/tsdicts.out
index 9df1434..3214609 100644
--- a/src/test/regress/expected/tsdicts.out
+++ b/src/test/regress/expected/tsdicts.out
@@ -5,6 +5,18 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+ERROR:  text search dictionary "public"."ispell" already exists
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+NOTICE:  text search dictionary "public"."ispell" already exists, skipping
 SELECT ts_lexize('ispell', 'skies');
  ts_lexize 
 -----------
@@ -232,6 +244,14 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+ERROR:  text search configuration "public"."ispell_tst" already exists
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
+NOTICE:  text search configuration "public"."ispell_tst" already exists, skipping
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
 	WITH ispell, english_stem;
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index d62f64f..f225ade 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -501,6 +501,8 @@ SELECT nspname, cfgname, rolname
 -- Text Search Template
 --
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE alt_ts_temp1 (lexize=dsimple_lexize);
+CREATE TEXT SEARCH TEMPLATE IF NOT EXISTS alt_ts_temp1 (lexize=dsimple_lexize);
 CREATE TEXT SEARCH TEMPLATE alt_ts_temp2 (lexize=dsimple_lexize);
 
 ALTER TEXT SEARCH TEMPLATE alt_ts_temp1 RENAME TO alt_ts_temp2; -- failed (name conflict)
@@ -521,6 +523,10 @@ SELECT nspname, tmplname
 
 CREATE TEXT SEARCH PARSER alt_ts_prs1
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TEXT SEARCH PARSER IF NOT EXISTS alt_ts_prs1
+    (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 CREATE TEXT SEARCH PARSER alt_ts_prs2
     (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
 
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index 84f9a4f..2d58c85 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -14,6 +14,18 @@ COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
 COMMENT ON AGGREGATE newavg (int4) IS NULL;
 
+-- test IF NOT EXISTS
+CREATE AGGREGATE newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+CREATE AGGREGATE IF NOT EXISTS newavg (
+   sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+   finalfunc = int8_avg,
+   initcond1 = '{0,0}'
+);
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4,
diff --git a/src/test/regress/sql/create_cast.sql b/src/test/regress/sql/create_cast.sql
index ad348da..ec9e266 100644
--- a/src/test/regress/sql/create_cast.sql
+++ b/src/test/regress/sql/create_cast.sql
@@ -29,18 +29,24 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
 
 -- Try binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION;
 SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
 SELECT casttestfunc('foo'::text::casttesttype); -- should work
 DROP CAST (text AS casttesttype); -- cleanup
 
 -- Try IMPLICIT binary coercion cast
 CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (text AS casttesttype) WITHOUT FUNCTION AS IMPLICIT;
 SELECT casttestfunc('foo'::text); -- Should work now
 
 -- Try I/O conversion cast.
 SELECT 1234::int4::casttesttype; -- No cast yet, should fail
 
 CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST (int4 AS casttesttype) WITH INOUT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH INOUT;
 SELECT 1234::int4::casttesttype; -- Should work now
 
 DROP CAST (int4 AS casttesttype);
@@ -51,4 +57,6 @@ CREATE FUNCTION int4_casttesttype(int4) RETURNS casttesttype LANGUAGE SQL AS
 $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
 
 CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
+CREATE CAST IF NOT EXISTS (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
 SELECT 1234::int4::casttesttype; -- Should work now
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index f7a372a..8278f88 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -1,14 +1,24 @@
 --
 -- CREATE_OPERATOR
 --
-
 CREATE OPERATOR ## (
    leftarg = path,
    rightarg = path,
    procedure = path_inter,
    commutator = ##
 );
-
+CREATE OPERATOR ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
+CREATE OPERATOR IF NOT EXISTS ## (
+   leftarg = path,
+   rightarg = path,
+   procedure = path_inter,
+   commutator = ##
+);
 CREATE OPERATOR <% (
    leftarg = point,
    rightarg = widget,
@@ -16,22 +26,18 @@ CREATE OPERATOR <% (
    commutator = >% ,
    negator = >=%
 );
-
 CREATE OPERATOR @#@ (
    rightarg = int8,		-- left unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
-
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
 
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index a4906b6..79e0181 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -16,6 +16,24 @@ CREATE TYPE widget (
    alignment = double
 );
 
+CREATE TYPE widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
+CREATE TYPE IF NOT EXISTS widget (
+   internallength = 24,
+   input = widget_in,
+   output = widget_out,
+   typmod_in = numerictypmodin,
+   typmod_out = numerictypmodout,
+   alignment = double
+);
+
 CREATE TYPE city_budget (
    internallength = 16,
    input = int44in,
@@ -28,6 +46,7 @@ CREATE TYPE city_budget (
 -- Test creation and destruction of shell types
 CREATE TYPE shell;
 CREATE TYPE shell;   -- fail, type already present
+CREATE TYPE IF NOT EXISTS shell;   -- do not fail, just skip
 DROP TYPE shell;
 DROP TYPE shell;     -- fail, type not exist
 
@@ -85,6 +104,10 @@ SELECT * FROM default_test;
 
 CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
 
+CREATE TYPE default_test_row AS (f1 text_w_default, f2 int42);
+
+CREATE TYPE IF NOT EXISTS default_test_row AS (f1 text_w_default, f2 int42);
+
 CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
   SELECT * FROM default_test;
 ' LANGUAGE SQL;
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 5af36af..f44f04c 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -2,6 +2,11 @@
 -- Test domains.
 --
 
+-- Test IF NOT EXISTS
+create domain domainifnotexists int4;
+create domain domainifnotexists int4;
+create domain if not exists domainifnotexists int4;
+
 -- Test Comment / Drop
 create domain domaindroptest int4;
 comment on domain domaindroptest is 'About to drop this..';
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index 88a835e..4f9ebb7 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -4,6 +4,10 @@
 
 CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
 
+CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+CREATE TYPE IF NOT EXISTS rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
 --
 -- Did it create the right number of rows?
 --
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 11d2ce5..190e1b3 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -18,6 +18,14 @@ create event trigger regress_event_trigger on elephant_bootstrap
 create event trigger regress_event_trigger on ddl_command_start
    execute procedure test_event_trigger();
 
+-- FAIL
+create event trigger regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+
+-- FAIL, but skipp
+create event trigger if not exists regress_event_trigger on ddl_command_start
+   execute procedure test_event_trigger();
+
 -- OK
 create event trigger regress_event_trigger_end on ddl_command_end
    execute procedure test_event_trigger();
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..32d5b95 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -1,6 +1,8 @@
 -- Tests for range data types.
 
 create type textrange as range (subtype=text, collation="C");
+create type textrange as range (subtype=text, collation="C");
+create type if not exists textrange as range (subtype=text, collation="C");
 
 --
 -- test input parser
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index a32e049..f055382 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -59,6 +59,7 @@ SELECT nextval('serialTest2_f6_seq');
 
 -- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
+CREATE SEQUENCE IF NOT EXISTS sequence_test;
 
 SELECT nextval('sequence_test'::text);
 SELECT nextval('sequence_test'::regclass);
diff --git a/src/test/regress/sql/tsdicts.sql b/src/test/regress/sql/tsdicts.sql
index 55afcec..2f66006 100644
--- a/src/test/regress/sql/tsdicts.sql
+++ b/src/test/regress/sql/tsdicts.sql
@@ -6,6 +6,16 @@ CREATE TEXT SEARCH DICTIONARY ispell (
                         DictFile=ispell_sample,
                         AffFile=ispell_sample
 );
+CREATE TEXT SEARCH DICTIONARY ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY IF NOT EXISTS ispell (
+                        Template=ispell,
+                        DictFile=ispell_sample,
+                        AffFile=ispell_sample
+);
 
 SELECT ts_lexize('ispell', 'skies');
 SELECT ts_lexize('ispell', 'bookings');
@@ -73,6 +83,12 @@ SELECT ts_lexize('thesaurus', 'one');
 CREATE TEXT SEARCH CONFIGURATION ispell_tst (
 						COPY=english
 );
+CREATE TEXT SEARCH CONFIGURATION ispell_tst (
+						COPY=english
+);
+CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS ispell_tst (
+						COPY=english
+);
 
 ALTER TEXT SEARCH CONFIGURATION ispell_tst ALTER MAPPING FOR
 	word, numword, asciiword, hword, numhword, asciihword, hword_part, hword_numpart, hword_asciipart
#30Stephen Frost
sfrost@snowman.net
In reply to: Robert Haas (#13)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

All,

* Robert Haas (robertmhaas@gmail.com) wrote:

On Wed, Jun 12, 2013 at 3:00 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

On 6/12/13 1:29 PM, Fabrízio de Royes Mello wrote:

- CREATE AGGREGATE [ IF NOT EXISTS ] ...
- CREATE CAST [ IF NOT EXISTS ] ...
- CREATE COLLATION [ IF NOT EXISTS ] ...
- CREATE OPERATOR [ IF NOT EXISTS ] ...
- CREATE TEXT SEARCH {PARSER | DICTIONARY | TEMPLATE | CONFIGURATION} [
IF NOT EXISTS ] ...
- CREATE TYPE [ IF NOT EXISTS ] ... [AS [{ENUM | RANGE}] (...)]

I'm wondering where "IF NOT EXISTS" and "OR REPLACE" will meet.

I kind of don't see the point of having IF NOT EXISTS for things that
have OR REPLACE, and am generally in favor of implementing OR REPLACE
rather than IF NOT EXISTS where possible. The point is usually to get
the object to a known state, and OR REPLACE will generally accomplish
that better than IF NOT EXISTS. However, if the object has complex
structure (like a table that contains data) then "replacing" it is a
bad plan, so IF NOT EXISTS is really the best you can do - and it's
still useful, even if it does require more care.

This patch is in the most recent commitfest and marked as Ready for
Committer, so I started reviewing it and came across the above.

I find myself mostly agreeing with the above comments from Robert, but
it doesn't seem like we've really done a comprehensive review of the
various commands to make a 'command' decision on each as to if it should
have IF NOT EXISTS or OR REPLACE options.

The one difficulty that I do see with the 'OR REPLACE' option is when we
can't simply replace an existing object due to dependencies on the
existing definition of that object. Still, if that's the case, wouldn't
you want an error? The 'IF NOT EXISTS' case is the no-error option, but
then you might not know what kind of state the system is in.

Fabrízio, can you clarify the use-case for things like CREATE AGGREGATE
to have IF NOT EXISTS rather than OR REPLACE, or if there is a reason
why both should exist? Complicating our CREATE options is not something
we really wish to do without good reason and we certainly don't want to
add something now that we'll wish to remove in another version or two.

Thanks!

Stephen

#31Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#30)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

Stephen Frost <sfrost@snowman.net> writes:

* Robert Haas (robertmhaas@gmail.com) wrote:

I kind of don't see the point of having IF NOT EXISTS for things that
have OR REPLACE, and am generally in favor of implementing OR REPLACE
rather than IF NOT EXISTS where possible. The point is usually to get
the object to a known state, and OR REPLACE will generally accomplish
that better than IF NOT EXISTS. However, if the object has complex
structure (like a table that contains data) then "replacing" it is a
bad plan, so IF NOT EXISTS is really the best you can do - and it's
still useful, even if it does require more care.

This patch is in the most recent commitfest and marked as Ready for
Committer, so I started reviewing it and came across the above.

I find myself mostly agreeing with the above comments from Robert, but
it doesn't seem like we've really done a comprehensive review of the
various commands to make a 'command' decision on each as to if it should
have IF NOT EXISTS or OR REPLACE options.

There's been pretty extensive theorizing about this in the past (try
searching the pghackers archives for "CINE" and "COR"), and I think the
rough consensus was that it's hard to do COR sensibly for objects
containing persistent state (ie tables) or with separately-declarable
substructure (again, mostly tables, though composite types have some of
the same issues). However, if COR does make sense then CINE is an
inferior alternative, because of the issue about not knowing the resulting
state of the object for sure.

Given this list I would absolutely reject CINE for aggregates (why in the
world would we make them act differently from functions?), and likewise
for casts, collations, operators, and types. I don't see any reason not
to prefer COR for these object kinds. There is room for argument about
the text search stuff, though, because of the fact that some of the text
search object types have separately declarable substructure.

The one difficulty that I do see with the 'OR REPLACE' option is when we
can't simply replace an existing object due to dependencies on the
existing definition of that object. Still, if that's the case, wouldn't
you want an error?

The main knock on COR is that there's no way for the system to completely
protect itself from the possibility that you replaced the object
definition with something that behaves incompatibly. For instance, if we
had COR for collations and you redefined a collation, that might (or might
not) break indexes whose ordering depends on that collation. However,
we already bought into that type of risk when we invented COR for
functions, and by and large there have been few complaints about it.
The ability to substitute an improved version of a function seems to be
worth the risks of substituting a broken version.

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

#32Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#31)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

2014-01-19 Tom Lane <tgl@sss.pgh.pa.us>:

Stephen Frost <sfrost@snowman.net> writes:

* Robert Haas (robertmhaas@gmail.com) wrote:

I kind of don't see the point of having IF NOT EXISTS for things that
have OR REPLACE, and am generally in favor of implementing OR REPLACE
rather than IF NOT EXISTS where possible. The point is usually to get
the object to a known state, and OR REPLACE will generally accomplish
that better than IF NOT EXISTS. However, if the object has complex
structure (like a table that contains data) then "replacing" it is a
bad plan, so IF NOT EXISTS is really the best you can do - and it's
still useful, even if it does require more care.

This patch is in the most recent commitfest and marked as Ready for
Committer, so I started reviewing it and came across the above.

I find myself mostly agreeing with the above comments from Robert, but
it doesn't seem like we've really done a comprehensive review of the
various commands to make a 'command' decision on each as to if it should
have IF NOT EXISTS or OR REPLACE options.

There's been pretty extensive theorizing about this in the past (try
searching the pghackers archives for "CINE" and "COR"), and I think the
rough consensus was that it's hard to do COR sensibly for objects
containing persistent state (ie tables) or with separately-declarable
substructure (again, mostly tables, though composite types have some of
the same issues). However, if COR does make sense then CINE is an
inferior alternative, because of the issue about not knowing the resulting
state of the object for sure.

Given this list I would absolutely reject CINE for aggregates (why in the
world would we make them act differently from functions?), and likewise
for casts, collations, operators, and types. I don't see any reason not
to prefer COR for these object kinds. There is room for argument about
the text search stuff, though, because of the fact that some of the text
search object types have separately declarable substructure.

The one difficulty that I do see with the 'OR REPLACE' option is when we
can't simply replace an existing object due to dependencies on the
existing definition of that object. Still, if that's the case, wouldn't
you want an error?

The main knock on COR is that there's no way for the system to completely
protect itself from the possibility that you replaced the object
definition with something that behaves incompatibly. For instance, if we
had COR for collations and you redefined a collation, that might (or might
not) break indexes whose ordering depends on that collation. However,
we already bought into that type of risk when we invented COR for
functions, and by and large there have been few complaints about it.
The ability to substitute an improved version of a function seems to be
worth the risks of substituting a broken version.

regards, tom lane

I agree with Tom proposal - CINE - where object holds data, COR everywhere
else.

But it means, so all functionality from this patch have to be rewritten :(

Regards

Pavel

Show quoted text

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

#33Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavel Stehule (#32)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

Pavel Stehule escribi�:

I agree with Tom proposal - CINE - where object holds data, COR everywhere
else.

But it means, so all functionality from this patch have to be rewritten :(

So we return this patch with feedback, right? I don't think it's
reasonable to continue waiting this late.

I have marked as such in the CF app.

--
�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

#34Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Stephen Frost (#30)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Sat, Jan 18, 2014 at 11:12 PM, Stephen Frost <sfrost@snowman.net> wrote:

Fabrízio, can you clarify the use-case for things like CREATE AGGREGATE
to have IF NOT EXISTS rather than OR REPLACE, or if there is a reason
why both should exist? Complicating our CREATE options is not something
we really wish to do without good reason and we certainly don't want to
add something now that we'll wish to remove in another version or two.

Hi Stephen,

First I'm really sorry about the long time without an answer. I'm very busy
in this start of the year.

Well I have a scenario with many servers to deploy DDL scripts, and most of
them we must run without transaction control because some tasks like CREATE
INDEX CONCURRENTLY, DROP/CREATE DATABASE, CLUSTER, etc.

When an error occurs the script stops, but the previous commands was
commited, then we must review the script to comment parts that was already
executed and then run it again. Until now is not a really trouble, but in
some cases we must deploy another DDL script that contains a new version of
some object before we finish to fix the previous version that was in
production, and if we have CINE for all CREATE objects this task will more
easy because we just run it again without care if will replace the content
and do not produce an error.

I know that is a very specific case, but in my mind I don't see any problem
to have CINE and COR to this objects. The behavior is totally different.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#35Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Alvaro Herrera (#33)
Re: Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Fri, Feb 28, 2014 at 5:05 PM, Alvaro Herrera <alvherre@2ndquadrant.com>
wrote:

Pavel Stehule escribió:

I agree with Tom proposal - CINE - where object holds data, COR

everywhere

else.

But it means, so all functionality from this patch have to be rewritten

:(

So we return this patch with feedback, right? I don't think it's
reasonable to continue waiting this late.

I have marked as such in the CF app.

Sorry guys... I'm very busy in this start of the year, so I have no time to
dedicate to this patch. Maybe in the next commit fest I have time and do a
rework on it.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#36Tom Lane
tgl@sss.pgh.pa.us
In reply to: Fabrízio de Royes Mello (#34)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

=?ISO-8859-1?Q?Fabr=EDzio_de_Royes_Mello?= <fabriziomello@gmail.com> writes:

On Sat, Jan 18, 2014 at 11:12 PM, Stephen Frost <sfrost@snowman.net> wrote:

Fabr�zio, can you clarify the use-case for things like CREATE AGGREGATE
to have IF NOT EXISTS rather than OR REPLACE, or if there is a reason
why both should exist? Complicating our CREATE options is not something
we really wish to do without good reason and we certainly don't want to
add something now that we'll wish to remove in another version or two.

Well I have a scenario with many servers to deploy DDL scripts, and most of
them we must run without transaction control because some tasks like CREATE
INDEX CONCURRENTLY, DROP/CREATE DATABASE, CLUSTER, etc.

When an error occurs the script stops, but the previous commands was
commited, then we must review the script to comment parts that was already
executed and then run it again. Until now is not a really trouble, but in
some cases we must deploy another DDL script that contains a new version of
some object before we finish to fix the previous version that was in
production, and if we have CINE for all CREATE objects this task will more
easy because we just run it again without care if will replace the content
and do not produce an error.

Why wouldn't COR semantics answer that requirement just as well, if not
better?

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

#37Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Tom Lane (#36)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Sat, Mar 1, 2014 at 2:11 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

=?ISO-8859-1?Q?Fabr=EDzio_de_Royes_Mello?= <fabriziomello@gmail.com>

writes:

On Sat, Jan 18, 2014 at 11:12 PM, Stephen Frost <sfrost@snowman.net>

wrote:

Fabrízio, can you clarify the use-case for things like CREATE AGGREGATE
to have IF NOT EXISTS rather than OR REPLACE, or if there is a reason
why both should exist? Complicating our CREATE options is not

something

we really wish to do without good reason and we certainly don't want to
add something now that we'll wish to remove in another version or two.

Well I have a scenario with many servers to deploy DDL scripts, and

most of

them we must run without transaction control because some tasks like

CREATE

INDEX CONCURRENTLY, DROP/CREATE DATABASE, CLUSTER, etc.

When an error occurs the script stops, but the previous commands was
commited, then we must review the script to comment parts that was

already

executed and then run it again. Until now is not a really trouble, but

in

some cases we must deploy another DDL script that contains a new

version of

some object before we finish to fix the previous version that was in
production, and if we have CINE for all CREATE objects this task will

more

easy because we just run it again without care if will replace the

content

and do not produce an error.

Why wouldn't COR semantics answer that requirement just as well, if not
better?

Just because it will replace the object content... and in some cases this
cannot happen because it will regress the schema to an old version.

I know it's a very specific use case, but in a scenario with many servers
and many automated tasks in different pipelines, CINE will be very useful.
I have this kind of troubles mostly with functions (we use COR), and
sometimes we will discover that the production version of function is wrong
after we receive a user notify, and in this situation many times we spend a
lot of effort do fix the whole damage.

Grettings,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQ

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Fabrízio de Royes Mello (#37)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

=?ISO-8859-1?Q?Fabr=EDzio_de_Royes_Mello?= <fabriziomello@gmail.com> writes:

On Sat, Mar 1, 2014 at 2:11 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

[ re schema upgrade scenarios ]
Why wouldn't COR semantics answer that requirement just as well, if not
better?

Just because it will replace the object content... and in some cases this
cannot happen because it will regress the schema to an old version.

That argument seems awfully darn flimsy. On what grounds would you argue
that the script you're sourcing contains versions you want of objects that
aren't there, but not versions you want of objects that are there? If
the script is out of date, it seems more likely that you'd end up with
back-rev versions of the newly created objects, which very possibly won't
interact well with the newer objects that were already in the database.

In any case, given the existence of DO it's simple to code up
create-if-not-exists behavior with a couple lines of plpgsql; that seems
to me to be a sufficient answer for corner cases. create-or-replace is
not equivalently fakable if the system doesn't supply the functionality.

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

#39Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Tom Lane (#38)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Sat, Mar 1, 2014 at 7:39 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

=?ISO-8859-1?Q?Fabr=EDzio_de_Royes_Mello?= <fabriziomello@gmail.com>

writes:

On Sat, Mar 1, 2014 at 2:11 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

[ re schema upgrade scenarios ]
Why wouldn't COR semantics answer that requirement just as well, if not
better?

Just because it will replace the object content... and in some cases

this

cannot happen because it will regress the schema to an old version.

That argument seems awfully darn flimsy.

Sorry, I know my use case is very specific...

We don't have this feature is a strong argument just because we can
implement COR instead? Or maybe just we don't want to add more complexity
to source code?

The complexity to source code added by this feature is minimal, but the
result is very useful, and can be used for many tools (i.e. rails
migrations, python alembic, doctrine, and others)

In any case, given the existence of DO it's simple to code up
create-if-not-exists behavior with a couple lines of plpgsql; that seems
to me to be a sufficient answer for corner cases. create-or-replace is
not equivalently fakable if the system doesn't supply the functionality.

You are completely right.

But we already have "DROP ... IF EXISTS", then I think if we would have
"CREATE ... IF NOT EXISTS" (the inverse behavior) will be very natural...
and I agree in implement "CREATE OR REPLACE" too.

Grettings,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#40Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Fabrízio de Royes Mello (#39)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Sun, Mar 2, 2014 at 1:04 AM, Fabrízio de Royes Mello <
fabriziomello@gmail.com> wrote:

On Sat, Mar 1, 2014 at 7:39 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

=?ISO-8859-1?Q?Fabr=EDzio_de_Royes_Mello?= <fabriziomello@gmail.com>

writes:

On Sat, Mar 1, 2014 at 2:11 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

[ re schema upgrade scenarios ]
Why wouldn't COR semantics answer that requirement just as well, if

not

better?

Just because it will replace the object content... and in some cases

this

cannot happen because it will regress the schema to an old version.

That argument seems awfully darn flimsy.

Sorry, I know my use case is very specific...

We don't have this feature is a strong argument just because we can

implement COR instead? Or maybe just we don't want to add more complexity
to source code?

The complexity to source code added by this feature is minimal, but the

result is very useful, and can be used for many tools (i.e. rails
migrations, python alembic, doctrine, and others)

In any case, given the existence of DO it's simple to code up
create-if-not-exists behavior with a couple lines of plpgsql; that seems
to me to be a sufficient answer for corner cases. create-or-replace is
not equivalently fakable if the system doesn't supply the functionality.

You are completely right.

But we already have "DROP ... IF EXISTS", then I think if we would have

"CREATE ... IF NOT EXISTS" (the inverse behavior) will be very natural...
and I agree in implement "CREATE OR REPLACE" too.

Hi all,

Sorry to return with this thread, but I think we missed something during
the review.

In 17th August 2013 [1]https://commitfest.postgresql.org/action/patch_view?id=1133 I added more code to patch [2]/messages/by-id/520FE6D4.8050402@timbira.com.br:

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]
- CREATE ROLE [ IF NOT EXISTS ]

Seems that no one reviewed this part or was rejected with others?

Regards,

[1]: https://commitfest.postgresql.org/action/patch_view?id=1133
[2]: /messages/by-id/520FE6D4.8050402@timbira.com.br

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#41Stephen Frost
sfrost@snowman.net
In reply to: Fabrízio de Royes Mello (#40)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]
- CREATE ROLE [ IF NOT EXISTS ]

Seems that no one reviewed this part or was rejected with others?

Why don't those fall into the same concern, specifically that what we
really want is 'CREATE-OR-REPLACE' semantics for them instead?

Thanks,

Stephen

#42Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Stephen Frost (#41)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Mon, Mar 31, 2014 at 4:52 PM, Stephen Frost <sfrost@snowman.net> wrote:

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]
- CREATE ROLE [ IF NOT EXISTS ]

Seems that no one reviewed this part or was rejected with others?

Why don't those fall into the same concern, specifically that what we
really want is 'CREATE-OR-REPLACE' semantics for them instead?

Ok, but I think this semantics is desirable just to "CREATE DOMAIN" and
"CREATE EVENT TRIGGER".

Isn't desirable add CINE to SEQUENCEs and ROLEs?

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#43Stephen Frost
sfrost@snowman.net
In reply to: Fabrízio de Royes Mello (#42)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

On Mon, Mar 31, 2014 at 4:52 PM, Stephen Frost <sfrost@snowman.net> wrote:

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]
- CREATE ROLE [ IF NOT EXISTS ]

Seems that no one reviewed this part or was rejected with others?

Why don't those fall into the same concern, specifically that what we
really want is 'CREATE-OR-REPLACE' semantics for them instead?

Ok, but I think this semantics is desirable just to "CREATE DOMAIN" and
"CREATE EVENT TRIGGER".

Isn't desirable add CINE to SEQUENCEs and ROLEs?

Why would it be difficult to have COR for sequences..? Or roles?

Thanks,

Stephen

#44Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Stephen Frost (#43)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Mon, Mar 31, 2014 at 5:00 PM, Stephen Frost <sfrost@snowman.net> wrote:

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

On Mon, Mar 31, 2014 at 4:52 PM, Stephen Frost <sfrost@snowman.net>

wrote:

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

- CREATE SEQUENCE [ IF NOT EXISTS ]
- CREATE DOMAIN [ IF NOT EXISTS ]
- CREATE EVENT TRIGGER [ IF NOT EXISTS ]
- CREATE ROLE [ IF NOT EXISTS ]

Seems that no one reviewed this part or was rejected with others?

Why don't those fall into the same concern, specifically that what we
really want is 'CREATE-OR-REPLACE' semantics for them instead?

Ok, but I think this semantics is desirable just to "CREATE DOMAIN" and
"CREATE EVENT TRIGGER".

Isn't desirable add CINE to SEQUENCEs and ROLEs?

Why would it be difficult to have COR for sequences..? Or roles?

Because they maintain user data?

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#45Stephen Frost
sfrost@snowman.net
In reply to: Fabrízio de Royes Mello (#44)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

Because they maintain user data?

Eh? You mean like the sequence #? Yes, I'd expect 'CREATE OR REPLACE
SEQUENCE' to want a minvalue or something on a 'replace' case to ensure
that it doesn't roll backwards unless explicitly asked for. Perhaps
the same for any non-default parameters as well, though I'd look at the
other COR cases to see what they do.

CREATE OR REPLACE ROLE is actually easier, no? All you'd be updating
are the various role attributes, I'd think, since only those are
available at CREATE time today. Any role memberships or ownership
would be left alone.

Thanks,

Stephen

#46Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Stephen Frost (#45)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Mon, Mar 31, 2014 at 5:46 PM, Stephen Frost <sfrost@snowman.net> wrote:

* Fabrízio de Royes Mello (fabriziomello@gmail.com) wrote:

Because they maintain user data?

Eh? You mean like the sequence #? Yes, I'd expect 'CREATE OR REPLACE
SEQUENCE' to want a minvalue or something on a 'replace' case to ensure
that it doesn't roll backwards unless explicitly asked for. Perhaps
the same for any non-default parameters as well, though I'd look at the
other COR cases to see what they do.

You mean if we execute 'CREATE OR REPLACE' must we verify the default
values of this statement and compare with the existing ones?

CREATE OR REPLACE ROLE is actually easier, no? All you'd be updating
are the various role attributes, I'd think, since only those are
available at CREATE time today. Any role memberships or ownership
would be left alone.

Think about the statements below:

CREATE ROLE test NOLOGIN;
CREATE OR REPLACE ROLE test;

If we execute the statements above the result should be the role 'test' can
login. Correct?

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#47Michael Paquier
michael.paquier@gmail.com
In reply to: Fabrízio de Royes Mello (#46)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Apr 1, 2014 at 7:28 AM, Fabrízio de Royes Mello
<fabriziomello@gmail.com> wrote:

Think about the statements below:

CREATE ROLE test NOLOGIN;
CREATE OR REPLACE ROLE test;

If we execute the statements above the result should be the role 'test' can
login. Correct?

Except if I am missing something, the second query means that it is
going to replace the existing user test with a new one, with the
settings specified in the 2nd query, all being default values. As the
default for login is NOLOGIN, the user test should not be able to log
in the server.
--
Michael

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

#48Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Michael Paquier (#47)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Apr 1, 2014 at 1:14 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:

On Tue, Apr 1, 2014 at 7:28 AM, Fabrízio de Royes Mello
<fabriziomello@gmail.com> wrote:

Think about the statements below:

CREATE ROLE test NOLOGIN;
CREATE OR REPLACE ROLE test;

If we execute the statements above the result should be the role 'test'

can

login. Correct?

Except if I am missing something, the second query means that it is
going to replace the existing user test with a new one, with the
settings specified in the 2nd query, all being default values. As the
default for login is NOLOGIN, the user test should not be able to log
in the server.

Yeah... you are correct... I meant:

CREATE ROLE test LOGIN;
CREATE OR REPLACE ROLE test;

Then the COR will replace the user 'test' setting a new default value to
NOLOGIN. Correct?

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#49Stephen Frost
sfrost@snowman.net
In reply to: Michael Paquier (#47)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

* Michael Paquier (michael.paquier@gmail.com) wrote:

On Tue, Apr 1, 2014 at 7:28 AM, Fabrízio de Royes Mello
<fabriziomello@gmail.com> wrote:

Think about the statements below:

CREATE ROLE test NOLOGIN;
CREATE OR REPLACE ROLE test;

If we execute the statements above the result should be the role 'test' can
login. Correct?

Except if I am missing something, the second query means that it is
going to replace the existing user test with a new one, with the
settings specified in the 2nd query, all being default values. As the
default for login is NOLOGIN, the user test should not be able to log
in the server.

That's more-or-less the behavior we're trying to work out. I've been
meaning to go back and look at what we've been doing with the existing
COR cases and just haven't gotten to it yet. The pertinent question
being if we assume the user intended for the values not specified to be
reset to their defaults, or not.

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail. Of course, were a user to use 'drop if exists'
followed by a 'create', they'd get the same behavior.. However, 'create
if not exists' would leave the sequence alone, but in a potentially
unknown state.

Thanks,

Stephen

#50Michael Paquier
michael.paquier@gmail.com
In reply to: Stephen Frost (#49)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Apr 1, 2014 at 1:34 PM, Stephen Frost <sfrost@snowman.net> wrote:

* Michael Paquier (michael.paquier@gmail.com) wrote:

On Tue, Apr 1, 2014 at 7:28 AM, Fabrízio de Royes Mello
<fabriziomello@gmail.com> wrote:

Think about the statements below:

CREATE ROLE test NOLOGIN;
CREATE OR REPLACE ROLE test;

If we execute the statements above the result should be the role 'test' can
login. Correct?

Except if I am missing something, the second query means that it is
going to replace the existing user test with a new one, with the
settings specified in the 2nd query, all being default values. As the
default for login is NOLOGIN, the user test should not be able to log
in the server.

That's more-or-less the behavior we're trying to work out. I've been
meaning to go back and look at what we've been doing with the existing
COR cases and just haven't gotten to it yet.

For example, on views, COR fails if it the new view does not contain
the old list of columns, same order and same data type, and can be
completed with new columns. The ownership of the view remains the same
as well. For functions, the argument types and return type need to
remain the same. As I understand, COR are useful because they
guarantee that no objects depending on it would be broken and are made
when a user wants to extend an object or redefine its internals. For
example, we should not allow that IMO:
CREATE ROLE foo LOGIN REPLICATION; -- ok
CREATE OR REPLACE ROLE foo NOREPLICATION; --error
Because with the 2nd query replication would break replication.

For roles, I am not completely sure how you would to that, but I would
imagine that you would need to keep track of all the parameters are
using non-default settings and specified directly by the user in
CREATE ROLE/USER. Then COR would fail if user tries to change some of
those parameters to values that do not map the non-default ones in the
first query (by tracking them in a new pg_authid column, berk, without
thinking about complications induced by IN ROLE, IN GROUP and
friends...). Perhaps I am thinking too much though.

The pertinent question being if we assume the user intended for the
values not specified to be reset to their defaults, or not.

Isn't it what ALTER ROLE aims at?

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail. Of course, were a user to use 'drop if exists'
followed by a 'create', they'd get the same behavior.. However, 'create
if not exists' would leave the sequence alone, but in a potentially
unknown state.

You could face failures on a serial column as well by changing the
increment sign of its sequence with a COR, so you would need more
guarantees than a min value.
Regards,
--
Michael

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

#51Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#49)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

Stephen Frost <sfrost@snowman.net> writes:

* Michael Paquier (michael.paquier@gmail.com) wrote:

Except if I am missing something, the second query means that it is
going to replace the existing user test with a new one, with the
settings specified in the 2nd query, all being default values. As the
default for login is NOLOGIN, the user test should not be able to log
in the server.

That's more-or-less the behavior we're trying to work out. I've been
meaning to go back and look at what we've been doing with the existing
COR cases and just haven't gotten to it yet. The pertinent question
being if we assume the user intended for the values not specified to be
reset to their defaults, or not.

Yes, it has to be that way. The entire argument for COR hinges on the
assumption that if you execute the statement, and it succeeds, the
properties of the object are equivalent to what they'd be if there had
been no predecessor object. Otherwise it's just the same as CINE,
which offers no guarantees worth mentioning about the object's
properties.

I'm willing to bend that to the extent of saying that COR leaves in place
subsidiary properties that you might add *with additional statements* ---
for example, foreign keys for a table, or privilege grants for a role.
But the properties of the role itself have to be predictable from the COR
statement, or it's useless.

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail.

Yeah.  Sequences do have contained data, which makes COR harder to define
--- that's part of the reason why we have CINE not COR for tables, and
maybe we have to do the same for sequences.  The point being exactly
that if you use CINE, you're implicitly accepting that you don't know
the ensuing state fully.

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

#52Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#51)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Apr 1, 2014 at 10:03 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm willing to bend that to the extent of saying that COR leaves in place
subsidiary properties that you might add *with additional statements* ---
for example, foreign keys for a table, or privilege grants for a role.
But the properties of the role itself have to be predictable from the COR
statement, or it's useless.

+1.

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail.

Yeah.  Sequences do have contained data, which makes COR harder to define
--- that's part of the reason why we have CINE not COR for tables, and
maybe we have to do the same for sequences.  The point being exactly
that if you use CINE, you're implicitly accepting that you don't know
the ensuing state fully.

Yeah. I think CINE is more sensible than COR for sequences, for
precisely the reason that they do have contained data (even if it's
basically only one value).

--
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

#53Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Robert Haas (#52)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Apr 1, 2014 at 2:46 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 1, 2014 at 10:03 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm willing to bend that to the extent of saying that COR leaves in place
subsidiary properties that you might add *with additional statements* ---
for example, foreign keys for a table, or privilege grants for a role.
But the properties of the role itself have to be predictable from the COR
statement, or it's useless.

+1.

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail.

Yeah.  Sequences do have contained data, which makes COR harder to define
--- that's part of the reason why we have CINE not COR for tables, and
maybe we have to do the same for sequences.  The point being exactly
that if you use CINE, you're implicitly accepting that you don't know
the ensuing state fully.

Yeah. I think CINE is more sensible than COR for sequences, for
precisely the reason that they do have contained data (even if it's
basically only one value).

Well then I'll separate CINE for sequences for the previous rejected... is
this a material for 9.5?

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

#54Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Robert Haas (#52)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Apr 1, 2014 at 2:46 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail.

Yeah. Sequences do have contained data, which makes COR harder to

define

--- that's part of the reason why we have CINE not COR for tables, and
maybe we have to do the same for sequences.  The point being exactly
that if you use CINE, you're implicitly accepting that you don't know
the ensuing state fully.

Yeah. I think CINE is more sensible than COR for sequences, for
precisely the reason that they do have contained data (even if it's
basically only one value).

The attached patch contains CINE for sequences.

I just strip this code from the patch rejected before.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog sobre TI: http://fabriziomello.blogspot.com
Perfil Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello

Attachments:

create_sequence_if_not_exists_v1.patchtext/x-diff; charset=US-ASCII; name=create_sequence_if_not_exists_v1.patchDownload
diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml
index 70b9f3d..de85b18 100644
--- a/doc/src/sgml/ref/create_sequence.sgml
+++ b/doc/src/sgml/ref/create_sequence.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE [ TEMPORARY | TEMP ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
+CREATE [ TEMPORARY | TEMP ] [ IF NOT EXISTS ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
     [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ]
@@ -90,6 +90,16 @@ SELECT * FROM <replaceable>name</replaceable>;
    </varlistentry>
 
    <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do nothing (except issuing a notice) if a sequence with the same name
+      already exists.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index ed696be..54be1b8 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -122,6 +122,17 @@ DefineSequence(CreateSeqStmt *seq)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("unlogged sequences are not supported")));
 
+	/* Check for IF NOT EXISTS clause */
+	RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid);
+	if (seq->if_not_exists && OidIsValid(seqoid))
+	{
+		ereport(NOTICE,
+				(errcode(ERRCODE_DUPLICATE_TABLE),
+				 errmsg("relation \"%s\" already exists, skipping",
+						seq->sequence->relname)));
+		return seqoid;
+	}
+
 	/* Check and set all option values */
 	init_params(seq->options, true, &new, &owned_by);
 
@@ -210,7 +221,7 @@ DefineSequence(CreateSeqStmt *seq)
 	stmt->options = NIL;
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
-	stmt->if_not_exists = false;
+	stmt->if_not_exists = seq->if_not_exists;
 
 	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
 	Assert(seqoid != InvalidOid);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 98ad910..fecf4b7 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3317,6 +3317,7 @@ _copyCreateSeqStmt(const CreateSeqStmt *from)
 	COPY_NODE_FIELD(sequence);
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(ownerId);
+	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 9901d23..21663fb 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1565,6 +1565,7 @@ _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(ownerId);
+	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7b9895d..27c24ea 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3391,6 +3391,17 @@ CreateSeqStmt:
 					n->sequence = $4;
 					n->options = $5;
 					n->ownerId = InvalidOid;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList
+				{
+					CreateSeqStmt *n = makeNode(CreateSeqStmt);
+					$7->relpersistence = $2;
+					n->sequence = $7;
+					n->options = $8;
+					n->ownerId = InvalidOid;
+					n->if_not_exists = true;
 					$$ = (Node *)n;
 				}
 		;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 18d4991..3facff7 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1941,6 +1941,7 @@ typedef struct CreateSeqStmt
 	RangeVar   *sequence;		/* the sequence to create */
 	List	   *options;
 	Oid			ownerId;		/* ID of owner, or InvalidOid for default */
+	bool		if_not_exists;	/* skip error if a Sequence already exists */
 } CreateSeqStmt;
 
 typedef struct AlterSeqStmt
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 8fcb700..a27b5fd 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -91,6 +91,8 @@ SELECT nextval('serialTest2_f6_seq');
 
 -- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
+CREATE SEQUENCE IF NOT EXISTS sequence_test;
+NOTICE:  relation "sequence_test" already exists, skipping
 SELECT nextval('sequence_test'::text);
  nextval 
 ---------
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index be5e9a9..8d3b700 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -59,6 +59,7 @@ SELECT nextval('serialTest2_f6_seq');
 
 -- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
+CREATE SEQUENCE IF NOT EXISTS sequence_test;
 
 SELECT nextval('sequence_test'::text);
 SELECT nextval('sequence_test'::regclass);
#55Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Fabrízio de Royes Mello (#54)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 04/14/2014 10:31 PM, Fabr�zio de Royes Mello wrote:

On Tue, Apr 1, 2014 at 2:46 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Where this is a bit more interesting is in the case of sequences, where
resetting the sequence to zero may cause further inserts into an
existing table to fail.

Yeah. Sequences do have contained data, which makes COR harder to

define

--- that's part of the reason why we have CINE not COR for tables, and
maybe we have to do the same for sequences.  The point being exactly
that if you use CINE, you're implicitly accepting that you don't know
the ensuing state fully.

Yeah. I think CINE is more sensible than COR for sequences, for
precisely the reason that they do have contained data (even if it's
basically only one value).

The attached patch contains CINE for sequences.

I just strip this code from the patch rejected before.

Committed with minor changes:

* The documentation promised too much. It said that it would not throw
an error "if a sequence with the same name exists". In fact, it will not
throw an error if any relation with the same name exists. I rewrote that
paragraph to emphasize that more, re-using the phrases from the CREATE
TABLE manual page.

* don't call RangeVarGetAndCheckCreationNamespace unnecessarily when IF
NOT EXISTS is not used.

- Heikki

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

#56Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Heikki Linnakangas (#55)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Aug 26, 2014 at 10:20 AM, Heikki Linnakangas <
hlinnakangas@vmware.com> wrote:

On 04/14/2014 10:31 PM, Fabrízio de Royes Mello wrote:

On Tue, Apr 1, 2014 at 2:46 PM, Robert Haas <robertmhaas@gmail.com>
wrote:

Where this is a bit more interesting is in the case of sequences, where

resetting the sequence to zero may cause further inserts into an
existing table to fail.

Yeah. Sequences do have contained data, which makes COR harder to

define

--- that's part of the reason why we have CINE not COR for tables, and

maybe we have to do the same for sequences. The point being exactly
that if you use CINE, you're implicitly accepting that you don't know
the ensuing state fully.

Yeah. I think CINE is more sensible than COR for sequences, for
precisely the reason that they do have contained data (even if it's
basically only one value).

The attached patch contains CINE for sequences.

I just strip this code from the patch rejected before.

Committed with minor changes:

* The documentation promised too much. It said that it would not throw an
error "if a sequence with the same name exists". In fact, it will not throw
an error if any relation with the same name exists. I rewrote that
paragraph to emphasize that more, re-using the phrases from the CREATE
TABLE manual page.

* don't call RangeVarGetAndCheckCreationNamespace unnecessarily when IF
NOT EXISTS is not used.

Thanks!

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog: http://fabriziomello.github.io
Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello
Github: http://github.com/fabriziomello

#57Marti Raudsepp
marti@juffo.org
In reply to: Heikki Linnakangas (#55)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Tue, Aug 26, 2014 at 4:20 PM, Heikki Linnakangas
<hlinnakangas@vmware.com> wrote:

On 04/14/2014 10:31 PM, Fabrízio de Royes Mello wrote:

The attached patch contains CINE for sequences.

I just strip this code from the patch rejected before.

Committed with minor changes

Hmm, the CommitFest app lists Marko Tiikkaja as the reviewer, but I
can't find his review anywhere...

The documentation claims:
CREATE [ IF NOT EXISTS ] SEQUENCE name
But grammar implements it the other way around:
CREATE SEQUENCE IF NOT EXISTS name;

Regards,
Marti

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

#58Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Marti Raudsepp (#57)
1 attachment(s)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On Thu, Oct 2, 2014 at 9:38 PM, Marti Raudsepp <marti@juffo.org> wrote:

On Tue, Aug 26, 2014 at 4:20 PM, Heikki Linnakangas
<hlinnakangas@vmware.com> wrote:

On 04/14/2014 10:31 PM, Fabrízio de Royes Mello wrote:

The attached patch contains CINE for sequences.

I just strip this code from the patch rejected before.

Committed with minor changes

Hmm, the CommitFest app lists Marko Tiikkaja as the reviewer, but I
can't find his review anywhere...

Maybe he have no time to review it.

The documentation claims:
CREATE [ IF NOT EXISTS ] SEQUENCE name
But grammar implements it the other way around:
CREATE SEQUENCE IF NOT EXISTS name;

You are correct. Fix attached.

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog: http://fabriziomello.github.io
Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello
Github: http://github.com/fabriziomello

Attachments:

fix_create_sequence_doc_v1.patchtext/x-diff; charset=US-ASCII; name=fix_create_sequence_doc_v1.patchDownload
diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml
index 7292c3f..9e364ff 100644
--- a/doc/src/sgml/ref/create_sequence.sgml
+++ b/doc/src/sgml/ref/create_sequence.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE [ TEMPORARY | TEMP ] [ IF NOT EXISTS ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
+CREATE [ TEMPORARY | TEMP ] SEQUENCE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
     [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ]
#59Marko Tiikkaja
marko@joh.to
In reply to: Fabrízio de Royes Mello (#58)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 10/3/14, 4:38 AM, Fabr�zio de Royes Mello wrote:

On Thu, Oct 2, 2014 at 9:38 PM, Marti Raudsepp <marti@juffo.org> wrote:

On Tue, Aug 26, 2014 at 4:20 PM, Heikki Linnakangas
<hlinnakangas@vmware.com> wrote:

On 04/14/2014 10:31 PM, Fabr�zio de Royes Mello wrote:

The attached patch contains CINE for sequences.

I just strip this code from the patch rejected before.

Committed with minor changes

Hmm, the CommitFest app lists Marko Tiikkaja as the reviewer, but I
can't find his review anywhere...

Maybe he have no time to review it.

Yes, Heikki picked this up before I had a chance to review it. Sorry
about that :-(

.marko

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

#60Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Fabrízio de Royes Mello (#58)
Re: Patch to add support of "IF NOT EXISTS" to others "CREATE" statements

On 10/03/2014 05:38 AM, Fabr�zio de Royes Mello wrote:

On Thu, Oct 2, 2014 at 9:38 PM, Marti Raudsepp <marti@juffo.org> wrote:

The documentation claims:
CREATE [ IF NOT EXISTS ] SEQUENCE name
But grammar implements it the other way around:
CREATE SEQUENCE IF NOT EXISTS name;

You are correct. Fix attached.

Thanks, fixed.

- Heikki

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