Add CREATE COLLATION IF NOT EXISTS clause

The core of the functionality was already implemented when
pg_import_system_collations was added.  This just exposes it as an
option in the SQL command.
This commit is contained in:
Peter Eisentraut 2017-02-08 22:51:09 -05:00
parent e403732ef6
commit 6d16ecc646
10 changed files with 47 additions and 6 deletions

View File

@ -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,17 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><literal>IF NOT EXISTS</literal></term>
<listitem>
<para>
Do not throw an error if a collation with the same name already exists.
A notice is issued in this case. Note that there is no guarantee that
the existing collation is anything like the one that would have been created.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>name</replaceable></term>

View File

@ -37,7 +37,7 @@
* CREATE COLLATION
*/
ObjectAddress
DefineCollation(ParseState *pstate, List *names, List *parameters)
DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists)
{
char *collName;
Oid collNamespace;
@ -137,7 +137,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters)
GetDatabaseEncoding(),
collcollate,
collctype,
false);
if_not_exists);
if (!OidIsValid(newoid))
return InvalidObjectAddress;

View File

@ -3105,6 +3105,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;
}

View File

@ -1211,6 +1211,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;
}

View File

@ -5610,6 +5610,16 @@ DefineStmt:
n->definition = $4;
$$ = (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
{
DefineStmt *n = makeNode(DefineStmt);
@ -5619,6 +5629,16 @@ DefineStmt:
n->definition = list_make1(makeDefElem("from", (Node *) $5, @5));
$$ = (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, @8));
n->if_not_exists = true;
$$ = (Node *)n;
}
;
definition: '(' def_list ')' { $$ = $2; }

View File

@ -1271,7 +1271,8 @@ ProcessUtilitySlow(ParseState *pstate,
Assert(stmt->args == NIL);
address = DefineCollation(pstate,
stmt->defnames,
stmt->definition);
stmt->definition,
stmt->if_not_exists);
break;
default:
elog(ERROR, "unrecognized define stmt type: %d",

View File

@ -18,7 +18,7 @@
#include "catalog/objectaddress.h"
#include "nodes/parsenodes.h"
extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters);
extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists);
extern void IsThereCollationInNamespace(const char *collname, Oid nspOid);
#endif /* COLLATIONCMDS_H */

View File

@ -2380,6 +2380,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 it already exists? */
} DefineStmt;
/* ----------------------

View File

@ -963,6 +963,10 @@ END
$$;
CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
ERROR: collation "test0" for encoding "UTF8" already exists
CREATE COLLATION IF NOT EXISTS test0 FROM "C"; -- ok, skipped
NOTICE: collation "test0" for encoding "UTF8" already exists, skipping
CREATE COLLATION IF NOT EXISTS test0 (locale = 'foo'); -- ok, skipped
NOTICE: collation "test0" for encoding "UTF8" already exists, skipping
do $$
BEGIN
EXECUTE 'CREATE COLLATION test1 (lc_collate = ' ||

View File

@ -325,6 +325,8 @@ BEGIN
END
$$;
CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
CREATE COLLATION IF NOT EXISTS test0 FROM "C"; -- ok, skipped
CREATE COLLATION IF NOT EXISTS test0 (locale = 'foo'); -- ok, skipped
do $$
BEGIN
EXECUTE 'CREATE COLLATION test1 (lc_collate = ' ||