mirror of https://github.com/postgres/postgres
- collowner field - CREATE COLLATION - ALTER COLLATION - DROP COLLATION - COMMENT ON COLLATION - integration with extensions - pg_dump support for the above - dependency management - psql tab completion - psql \dO commandpull/1/head
parent
d31e2a495b
commit
b313bca0af
@ -0,0 +1,128 @@ |
||||
<!-- |
||||
doc/src/sgml/ref/alter_collation.sgml |
||||
PostgreSQL documentation |
||||
--> |
||||
|
||||
<refentry id="SQL-ALTERCOLLATION"> |
||||
<refmeta> |
||||
<refentrytitle>ALTER COLLATION</refentrytitle> |
||||
<manvolnum>7</manvolnum> |
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo> |
||||
</refmeta> |
||||
|
||||
<refnamediv> |
||||
<refname>ALTER COLLATION</refname> |
||||
<refpurpose>change the definition of a collation</refpurpose> |
||||
</refnamediv> |
||||
|
||||
<indexterm zone="sql-altercollation"> |
||||
<primary>ALTER COLLATION</primary> |
||||
</indexterm> |
||||
|
||||
<refsynopsisdiv> |
||||
<synopsis> |
||||
ALTER COLLATION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable> |
||||
ALTER COLLATION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable> |
||||
ALTER COLLATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable> |
||||
</synopsis> |
||||
</refsynopsisdiv> |
||||
|
||||
<refsect1> |
||||
<title>Description</title> |
||||
|
||||
<para> |
||||
<command>ALTER COLLATION</command> changes the definition of a |
||||
collation. |
||||
</para> |
||||
|
||||
<para> |
||||
You must own the collation to use <command>ALTER COLLATION</>. |
||||
To alter the owner, you must also be a direct or indirect member of the new |
||||
owning role, and that role must have <literal>CREATE</literal> privilege on |
||||
the collation's schema. (These restrictions enforce that altering the |
||||
owner doesn't do anything you couldn't do by dropping and recreating the |
||||
collation. However, a superuser can alter ownership of any collation |
||||
anyway.) |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1> |
||||
<title>Parameters</title> |
||||
|
||||
<variablelist> |
||||
<varlistentry> |
||||
<term><replaceable class="parameter">name</replaceable></term> |
||||
<listitem> |
||||
<para> |
||||
The name (optionally schema-qualified) of an existing collation. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable class="parameter">new_name</replaceable></term> |
||||
<listitem> |
||||
<para> |
||||
The new name of the collation. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable class="parameter">new_owner</replaceable></term> |
||||
<listitem> |
||||
<para> |
||||
The new owner of the collation. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable class="parameter">new_schema</replaceable></term> |
||||
<listitem> |
||||
<para> |
||||
The new schema for the collation. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
</variablelist> |
||||
</refsect1> |
||||
|
||||
<refsect1> |
||||
<title>Examples</title> |
||||
|
||||
<para> |
||||
To rename the collation <literal>de_DE</literal> to |
||||
<literal>german</literal>: |
||||
<programlisting> |
||||
ALTER COLLATION "de_DE" RENAME TO german; |
||||
</programlisting> |
||||
</para> |
||||
|
||||
<para> |
||||
To change the owner of the collation <literal>en_US</literal> to |
||||
<literal>joe</literal>: |
||||
<programlisting> |
||||
ALTER COLLATION "en_US" OWNER TO joe; |
||||
</programlisting> |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1> |
||||
<title>Compatibility</title> |
||||
|
||||
<para> |
||||
There is no <command>ALTER COLLATION</command> statement in the SQL |
||||
standard. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1> |
||||
<title>See Also</title> |
||||
|
||||
<simplelist type="inline"> |
||||
<member><xref linkend="sql-createcollation"></member> |
||||
<member><xref linkend="sql-dropcollation"></member> |
||||
</simplelist> |
||||
</refsect1> |
||||
</refentry> |
@ -0,0 +1,175 @@ |
||||
<!-- doc/src/sgml/ref/create_collation.sgml --> |
||||
|
||||
<refentry id="SQL-CREATECOLLATION"> |
||||
<refmeta> |
||||
<refentrytitle>CREATE COLLATION</refentrytitle> |
||||
<manvolnum>7</manvolnum> |
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo> |
||||
</refmeta> |
||||
|
||||
<refnamediv> |
||||
<refname>CREATE COLLATION</refname> |
||||
<refpurpose>define a new collation</refpurpose> |
||||
</refnamediv> |
||||
|
||||
<indexterm zone="sql-createcollation"> |
||||
<primary>CREATE COLLATION</primary> |
||||
</indexterm> |
||||
|
||||
<refsynopsisdiv> |
||||
<synopsis> |
||||
CREATE COLLATION <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> |
||||
</synopsis> |
||||
</refsynopsisdiv> |
||||
|
||||
<refsect1 id="sql-createcollation-description"> |
||||
<title>Description</title> |
||||
|
||||
<para> |
||||
<command>CREATE COLLATION</command> defines a new collation using |
||||
the specified operating system locales or from an existing collation. |
||||
</para> |
||||
|
||||
<para> |
||||
To be able to create a collation, you must |
||||
have <literal>CREATE</literal> privilege on the destination schema. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
|
||||
<refsect1> |
||||
<title>Parameters</title> |
||||
|
||||
<variablelist> |
||||
<varlistentry> |
||||
<term><replaceable>name</replaceable></term> |
||||
|
||||
<listitem> |
||||
<para> |
||||
The name of the collation. The collation name can be |
||||
schema-qualified. If it is not, the collation is defined in the |
||||
current schema. The collation name must be unique within a |
||||
schema. (The system catalogs can contain collations with the |
||||
same name for other encodings, but these are not usable if the |
||||
database encoding does not match.) |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable>existing_collation</replaceable></term> |
||||
|
||||
<listitem> |
||||
<para> |
||||
The name of an existing collation to copy. The new collation |
||||
will have the same properties as the existing one, but they |
||||
will become independent objects. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable>locale</replaceable></term> |
||||
|
||||
<listitem> |
||||
<para> |
||||
This is a shortcut for setting <symbol>LC_COLLATE</symbol> |
||||
and <symbol>LC_CTYPE</symbol> at once. If you specify this, |
||||
you cannot specify either of the other parameters. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable>lc_collate</replaceable></term> |
||||
|
||||
<listitem> |
||||
<para> |
||||
Use the specified operating system locale for |
||||
the <symbol>LC_COLLATE</symbol> locale category. The locale |
||||
must be applicable to the current database encoding. |
||||
(See <xref linkend="sql-createdatabase"> for the precise |
||||
rules.) |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable>lc_ctype</replaceable></term> |
||||
|
||||
<listitem> |
||||
<para> |
||||
Use the specified operating system locale for |
||||
the <symbol>LC_CTYPE</symbol> locale category. The locale |
||||
must be applicable to the current database encoding. |
||||
(See <xref linkend="sql-createdatabase"> for the precise |
||||
rules.) |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
</variablelist> |
||||
</refsect1> |
||||
|
||||
|
||||
<refsect1 id="sql-createcollation-notes"> |
||||
<title>Notes</title> |
||||
|
||||
<para> |
||||
Use <command>DROP COLLATION</command> to remove user-defined collations. |
||||
</para> |
||||
|
||||
<para> |
||||
See <xref linkend="collation"> for more information about collation |
||||
support in PostgreSQL. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1 id="sql-createcollation-examples"> |
||||
<title>Examples</title> |
||||
|
||||
<para> |
||||
To create a collation from the locale <literal>fr_FR.utf8</literal> |
||||
(assuming the current database encoding is <literal>UTF8</literal>): |
||||
<programlisting> |
||||
CREATE COLLATION french (LOCALE = 'fr_FR.utf8'); |
||||
</programlisting> |
||||
</para> |
||||
|
||||
<para> |
||||
To create a collation from an existing collation: |
||||
<programlisting> |
||||
CREATE COLLATION german FROM "de_DE"; |
||||
</programlisting> |
||||
This can be convenient to be able to use operating-system |
||||
independent collation names in applications. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
|
||||
<refsect1 id="sql-createcollation-compat"> |
||||
<title>Compatibility</title> |
||||
|
||||
<para> |
||||
There is a <command>CREATE COLLATION</command> statement in the SQL |
||||
standard, but it is limited to copying an existing collation. The |
||||
syntax to create a new collation is |
||||
a <productname>PostgreSQL</productname> extension. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
|
||||
<refsect1 id="sql-createcollation-seealso"> |
||||
<title>See Also</title> |
||||
|
||||
<simplelist type="inline"> |
||||
<member><xref linkend="sql-altercollation"></member> |
||||
<member><xref linkend="sql-dropcollation"></member> |
||||
</simplelist> |
||||
</refsect1> |
||||
|
||||
</refentry> |
@ -0,0 +1,110 @@ |
||||
<!-- doc/src/sgml/ref/drop_collation.sgml --> |
||||
|
||||
<refentry id="SQL-DROPCOLLATION"> |
||||
<refmeta> |
||||
<refentrytitle>DROP COLLATION</refentrytitle> |
||||
<manvolnum>7</manvolnum> |
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo> |
||||
</refmeta> |
||||
|
||||
<refnamediv> |
||||
<refname>DROP COLLATION</refname> |
||||
<refpurpose>remove a collation</refpurpose> |
||||
</refnamediv> |
||||
|
||||
<indexterm zone="sql-dropcollation"> |
||||
<primary>DROP COLLATION</primary> |
||||
</indexterm> |
||||
|
||||
<refsynopsisdiv> |
||||
<synopsis> |
||||
DROP COLLATION [ IF EXISTS ] <replaceable>name</replaceable> [ CASCADE | RESTRICT ] |
||||
</synopsis> |
||||
</refsynopsisdiv> |
||||
|
||||
<refsect1 id="sql-dropcollation-description"> |
||||
<title>Description</title> |
||||
|
||||
<para> |
||||
<command>DROP COLLATION</command> removes a previously defined collation. |
||||
To be able to drop a collation, you must own the collation. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1> |
||||
<title>Parameters</title> |
||||
|
||||
<variablelist> |
||||
<varlistentry> |
||||
<term><literal>IF EXISTS</literal></term> |
||||
<listitem> |
||||
<para> |
||||
Do not throw an error if the collation does not exist. |
||||
A notice is issued in this case. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><replaceable>name</replaceable></term> |
||||
|
||||
<listitem> |
||||
<para> |
||||
The name of the collation. The collation name can be |
||||
schema-qualified. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><literal>CASCADE</literal></term> |
||||
<listitem> |
||||
<para> |
||||
Automatically drop objects that depend on the collation. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
|
||||
<varlistentry> |
||||
<term><literal>RESTRICT</literal></term> |
||||
<listitem> |
||||
<para> |
||||
Refuse to drop the collation if any objects depend on it. This |
||||
is the default. |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
</variablelist> |
||||
</refsect1> |
||||
|
||||
<refsect1 id="sql-dropcollation-examples"> |
||||
<title>Examples</title> |
||||
|
||||
<para> |
||||
To drop the collation named <literal>german</>: |
||||
<programlisting> |
||||
DROP COLLATION german; |
||||
</programlisting> |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1 id="sql-dropcollation-compat"> |
||||
<title>Compatibility</title> |
||||
|
||||
<para> |
||||
The <command>DROP COLLATION</command> command conforms to the |
||||
<acronym>SQL</acronym> standard, apart from the <literal>IF |
||||
EXISTS</> option, which is a <productname>PostgreSQL</> extension.. |
||||
</para> |
||||
</refsect1> |
||||
|
||||
<refsect1> |
||||
<title>See Also</title> |
||||
|
||||
<simplelist type="inline"> |
||||
<member><xref linkend="sql-altercollation"></member> |
||||
<member><xref linkend="sql-createcollation"></member> |
||||
</simplelist> |
||||
</refsect1> |
||||
|
||||
</refentry> |
@ -0,0 +1,163 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_collation.c |
||||
* routines to support manipulation of the pg_collation relation |
||||
* |
||||
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/catalog/pg_collation.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/heapam.h" |
||||
#include "access/sysattr.h" |
||||
#include "catalog/dependency.h" |
||||
#include "catalog/indexing.h" |
||||
#include "catalog/objectaccess.h" |
||||
#include "catalog/pg_collation.h" |
||||
#include "catalog/pg_collation_fn.h" |
||||
#include "catalog/pg_namespace.h" |
||||
#include "catalog/pg_proc.h" |
||||
#include "mb/pg_wchar.h" |
||||
#include "miscadmin.h" |
||||
#include "utils/acl.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/fmgroids.h" |
||||
#include "utils/rel.h" |
||||
#include "utils/syscache.h" |
||||
#include "utils/tqual.h" |
||||
|
||||
/*
|
||||
* CollationCreate |
||||
* |
||||
* Add a new tuple to pg_collation. |
||||
*/ |
||||
Oid |
||||
CollationCreate(const char *collname, Oid collnamespace, |
||||
Oid collowner, |
||||
int32 collencoding, |
||||
const char *collcollate, const char *collctype) |
||||
{ |
||||
int i; |
||||
Relation rel; |
||||
TupleDesc tupDesc; |
||||
HeapTuple tup; |
||||
bool nulls[Natts_pg_collation]; |
||||
Datum values[Natts_pg_collation]; |
||||
NameData name_name, name_collate, name_ctype; |
||||
Oid oid; |
||||
ObjectAddress myself, |
||||
referenced; |
||||
|
||||
AssertArg(collname); |
||||
AssertArg(collnamespace); |
||||
AssertArg(collowner); |
||||
AssertArg(collcollate); |
||||
AssertArg(collctype); |
||||
|
||||
/* make sure there is no existing collation of same name */ |
||||
if (SearchSysCacheExists3(COLLNAMEENCNSP, |
||||
PointerGetDatum(collname), |
||||
Int32GetDatum(collencoding), |
||||
ObjectIdGetDatum(collnamespace))) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_DUPLICATE_OBJECT), |
||||
errmsg("collation \"%s\" for encoding \"%s\" already exists", |
||||
collname, pg_encoding_to_char(collencoding)))); |
||||
|
||||
/* open pg_collation */ |
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
tupDesc = rel->rd_att; |
||||
|
||||
/* initialize nulls and values */ |
||||
for (i = 0; i < Natts_pg_collation; i++) |
||||
{ |
||||
nulls[i] = false; |
||||
values[i] = (Datum) NULL; |
||||
} |
||||
|
||||
/* form a tuple */ |
||||
namestrcpy(&name_name, collname); |
||||
values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name); |
||||
values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace); |
||||
values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner); |
||||
values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding); |
||||
namestrcpy(&name_collate, collcollate); |
||||
values[Anum_pg_collation_collcollate - 1] = NameGetDatum(&name_collate); |
||||
namestrcpy(&name_ctype, collctype); |
||||
values[Anum_pg_collation_collctype - 1] = NameGetDatum(&name_ctype); |
||||
|
||||
tup = heap_form_tuple(tupDesc, values, nulls); |
||||
|
||||
/* insert a new tuple */ |
||||
oid = simple_heap_insert(rel, tup); |
||||
Assert(OidIsValid(oid)); |
||||
|
||||
/* update the index if any */ |
||||
CatalogUpdateIndexes(rel, tup); |
||||
|
||||
myself.classId = CollationRelationId; |
||||
myself.objectId = HeapTupleGetOid(tup); |
||||
myself.objectSubId = 0; |
||||
|
||||
/* create dependency on namespace */ |
||||
referenced.classId = NamespaceRelationId; |
||||
referenced.objectId = collnamespace; |
||||
referenced.objectSubId = 0; |
||||
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); |
||||
|
||||
/* create dependency on owner */ |
||||
recordDependencyOnOwner(CollationRelationId, HeapTupleGetOid(tup), |
||||
collowner); |
||||
|
||||
/* dependency on extension */ |
||||
recordDependencyOnCurrentExtension(&myself); |
||||
|
||||
/* Post creation hook for new collation */ |
||||
InvokeObjectAccessHook(OAT_POST_CREATE, |
||||
CollationRelationId, HeapTupleGetOid(tup), 0); |
||||
|
||||
heap_freetuple(tup); |
||||
heap_close(rel, RowExclusiveLock); |
||||
|
||||
return oid; |
||||
} |
||||
|
||||
/*
|
||||
* RemoveCollationById |
||||
* |
||||
* Remove a tuple from pg_collation by Oid. This function is solely |
||||
* called inside catalog/dependency.c |
||||
*/ |
||||
void |
||||
RemoveCollationById(Oid collationOid) |
||||
{ |
||||
Relation rel; |
||||
HeapTuple tuple; |
||||
HeapScanDesc scan; |
||||
ScanKeyData scanKeyData; |
||||
|
||||
ScanKeyInit(&scanKeyData, |
||||
ObjectIdAttributeNumber, |
||||
BTEqualStrategyNumber, F_OIDEQ, |
||||
ObjectIdGetDatum(collationOid)); |
||||
|
||||
/* open pg_collation */ |
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
|
||||
scan = heap_beginscan(rel, SnapshotNow, |
||||
1, &scanKeyData); |
||||
|
||||
/* search for the target tuple */ |
||||
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) |
||||
simple_heap_delete(rel, &tuple->t_self); |
||||
else |
||||
elog(ERROR, "could not find tuple for collation %u", collationOid); |
||||
heap_endscan(scan); |
||||
heap_close(rel, RowExclusiveLock); |
||||
} |
@ -0,0 +1,401 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* collationcmds.c |
||||
* collation creation command support code |
||||
* |
||||
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/backend/commands/collationcmds.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/heapam.h" |
||||
#include "catalog/dependency.h" |
||||
#include "catalog/indexing.h" |
||||
#include "catalog/namespace.h" |
||||
#include "catalog/pg_collation.h" |
||||
#include "catalog/pg_collation_fn.h" |
||||
#include "commands/alter.h" |
||||
#include "commands/collationcmds.h" |
||||
#include "commands/dbcommands.h" |
||||
#include "commands/defrem.h" |
||||
#include "mb/pg_wchar.h" |
||||
#include "miscadmin.h" |
||||
#include "parser/parse_type.h" |
||||
#include "utils/acl.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/lsyscache.h" |
||||
#include "utils/syscache.h" |
||||
|
||||
static void AlterCollationOwner_internal(Relation rel, Oid collationOid, |
||||
Oid newOwnerId); |
||||
|
||||
/*
|
||||
* CREATE COLLATION |
||||
*/ |
||||
void |
||||
DefineCollation(List *names, List *parameters) |
||||
{ |
||||
char *collName; |
||||
Oid collNamespace; |
||||
AclResult aclresult; |
||||
ListCell *pl; |
||||
DefElem *fromEl = NULL; |
||||
DefElem *localeEl = NULL; |
||||
DefElem *lccollateEl = NULL; |
||||
DefElem *lcctypeEl = NULL; |
||||
char *collcollate = NULL; |
||||
char *collctype = NULL; |
||||
|
||||
collNamespace = QualifiedNameGetCreationNamespace(names, &collName); |
||||
|
||||
aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); |
||||
if (aclresult != ACLCHECK_OK) |
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, |
||||
get_namespace_name(collNamespace)); |
||||
|
||||
foreach(pl, parameters) |
||||
{ |
||||
DefElem *defel = (DefElem *) lfirst(pl); |
||||
DefElem **defelp; |
||||
|
||||
if (pg_strcasecmp(defel->defname, "from") == 0) |
||||
defelp = &fromEl; |
||||
else if (pg_strcasecmp(defel->defname, "locale") == 0) |
||||
defelp = &localeEl; |
||||
else if (pg_strcasecmp(defel->defname, "lc_collate") == 0) |
||||
defelp = &lccollateEl; |
||||
else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0) |
||||
defelp = &lcctypeEl; |
||||
else |
||||
{ |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_SYNTAX_ERROR), |
||||
errmsg("collation attribute \"%s\" not recognized", |
||||
defel->defname))); |
||||
break; |
||||
} |
||||
|
||||
*defelp = defel; |
||||
} |
||||
|
||||
if ((localeEl && (lccollateEl || lcctypeEl)) |
||||
|| (fromEl && list_length(parameters) != 1)) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_SYNTAX_ERROR), |
||||
errmsg("conflicting or redundant options"))); |
||||
|
||||
if (fromEl) |
||||
{ |
||||
Oid collid; |
||||
HeapTuple tp; |
||||
|
||||
collid = LookupCollation(NULL, defGetQualifiedName(fromEl), -1); |
||||
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid)); |
||||
if (!HeapTupleIsValid(tp)) |
||||
elog(ERROR, "cache lookup failed for collation %u", collid); |
||||
|
||||
collcollate = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collcollate)); |
||||
collctype = pstrdup(NameStr(((Form_pg_collation) GETSTRUCT(tp))->collctype)); |
||||
|
||||
ReleaseSysCache(tp); |
||||
} |
||||
|
||||
if (localeEl) |
||||
{ |
||||
collcollate = defGetString(localeEl); |
||||
collctype = defGetString(localeEl); |
||||
} |
||||
|
||||
if (lccollateEl) |
||||
collcollate = defGetString(lccollateEl); |
||||
|
||||
if (lcctypeEl) |
||||
collctype = defGetString(lcctypeEl); |
||||
|
||||
if (!collcollate) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("parameter \"lc_collate\" parameter must be specified"))); |
||||
|
||||
if (!collctype) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), |
||||
errmsg("parameter \"lc_ctype\" must be specified"))); |
||||
|
||||
check_encoding_locale_matches(GetDatabaseEncoding(), collcollate, collctype); |
||||
|
||||
CollationCreate(collName, |
||||
collNamespace, |
||||
GetUserId(), |
||||
GetDatabaseEncoding(), |
||||
collcollate, |
||||
collctype); |
||||
} |
||||
|
||||
/*
|
||||
* DROP COLLATION |
||||
*/ |
||||
void |
||||
DropCollationsCommand(DropStmt *drop) |
||||
{ |
||||
ObjectAddresses *objects; |
||||
ListCell *cell; |
||||
|
||||
/*
|
||||
* First we identify all the collations, then we delete them in a single |
||||
* performMultipleDeletions() call. This is to avoid unwanted DROP |
||||
* RESTRICT errors if one of the collations depends on another. (Not that |
||||
* that is very likely, but we may as well do this consistently.) |
||||
*/ |
||||
objects = new_object_addresses(); |
||||
|
||||
foreach(cell, drop->objects) |
||||
{ |
||||
List *name = (List *) lfirst(cell); |
||||
Oid collationOid; |
||||
HeapTuple tuple; |
||||
Form_pg_collation coll; |
||||
ObjectAddress object; |
||||
|
||||
collationOid = get_collation_oid(name, drop->missing_ok); |
||||
|
||||
if (!OidIsValid(collationOid)) |
||||
{ |
||||
ereport(NOTICE, |
||||
(errmsg("collation \"%s\" does not exist, skipping", |
||||
NameListToString(name)))); |
||||
continue; |
||||
} |
||||
|
||||
tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationOid)); |
||||
if (!HeapTupleIsValid(tuple)) |
||||
elog(ERROR, "cache lookup failed for collation %u", |
||||
collationOid); |
||||
coll = (Form_pg_collation) GETSTRUCT(tuple); |
||||
|
||||
/* Permission check: must own collation or its namespace */ |
||||
if (!pg_collation_ownercheck(collationOid, GetUserId()) && |
||||
!pg_namespace_ownercheck(coll->collnamespace, GetUserId())) |
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, |
||||
NameStr(coll->collname)); |
||||
|
||||
object.classId = CollationRelationId; |
||||
object.objectId = collationOid; |
||||
object.objectSubId = 0; |
||||
|
||||
add_exact_object_address(&object, objects); |
||||
|
||||
ReleaseSysCache(tuple); |
||||
} |
||||
|
||||
performMultipleDeletions(objects, drop->behavior); |
||||
|
||||
free_object_addresses(objects); |
||||
} |
||||
|
||||
/*
|
||||
* Rename collation |
||||
*/ |
||||
void |
||||
RenameCollation(List *name, const char *newname) |
||||
{ |
||||
Oid collationOid; |
||||
Oid namespaceOid; |
||||
HeapTuple tup; |
||||
Relation rel; |
||||
AclResult aclresult; |
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
|
||||
collationOid = get_collation_oid(name, false); |
||||
|
||||
tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collationOid)); |
||||
if (!HeapTupleIsValid(tup)) /* should not happen */ |
||||
elog(ERROR, "cache lookup failed for collation %u", collationOid); |
||||
|
||||
namespaceOid = ((Form_pg_collation) GETSTRUCT(tup))->collnamespace; |
||||
|
||||
/* make sure the new name doesn't exist */ |
||||
if (SearchSysCacheExists3(COLLNAMEENCNSP, |
||||
CStringGetDatum(newname), |
||||
Int32GetDatum(GetDatabaseEncoding()), |
||||
ObjectIdGetDatum(namespaceOid))) |
||||
ereport(ERROR, |
||||
(errcode(ERRCODE_DUPLICATE_OBJECT), |
||||
errmsg("collation \"%s\" for current database encoding \"%s\" already exists in schema \"%s\"", |
||||
newname, |
||||
GetDatabaseEncodingName(), |
||||
get_namespace_name(namespaceOid)))); |
||||
|
||||
/* must be owner */ |
||||
if (!pg_collation_ownercheck(collationOid, GetUserId())) |
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, |
||||
NameListToString(name)); |
||||
|
||||
/* must have CREATE privilege on namespace */ |
||||
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE); |
||||
if (aclresult != ACLCHECK_OK) |
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, |
||||
get_namespace_name(namespaceOid)); |
||||
|
||||
/* rename */ |
||||
namestrcpy(&(((Form_pg_collation) GETSTRUCT(tup))->collname), newname); |
||||
simple_heap_update(rel, &tup->t_self, tup); |
||||
CatalogUpdateIndexes(rel, tup); |
||||
|
||||
heap_close(rel, NoLock); |
||||
heap_freetuple(tup); |
||||
} |
||||
|
||||
/*
|
||||
* Change collation owner, by name |
||||
*/ |
||||
void |
||||
AlterCollationOwner(List *name, Oid newOwnerId) |
||||
{ |
||||
Oid collationOid; |
||||
Relation rel; |
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
|
||||
collationOid = get_collation_oid(name, false); |
||||
|
||||
AlterCollationOwner_internal(rel, collationOid, newOwnerId); |
||||
|
||||
heap_close(rel, NoLock); |
||||
} |
||||
|
||||
/*
|
||||
* Change collation owner, by oid |
||||
*/ |
||||
void |
||||
AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId) |
||||
{ |
||||
Relation rel; |
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
|
||||
AlterCollationOwner_internal(rel, collationOid, newOwnerId); |
||||
|
||||
heap_close(rel, NoLock); |
||||
} |
||||
|
||||
/*
|
||||
* AlterCollationOwner_internal |
||||
* |
||||
* Internal routine for changing the owner. rel must be pg_collation, already |
||||
* open and suitably locked; it will not be closed. |
||||
*/ |
||||
static void |
||||
AlterCollationOwner_internal(Relation rel, Oid collationOid, Oid newOwnerId) |
||||
{ |
||||
Form_pg_collation collForm; |
||||
HeapTuple tup; |
||||
|
||||
Assert(RelationGetRelid(rel) == CollationRelationId); |
||||
|
||||
tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collationOid)); |
||||
if (!HeapTupleIsValid(tup)) /* should not happen */ |
||||
elog(ERROR, "cache lookup failed for collation %u", collationOid); |
||||
|
||||
collForm = (Form_pg_collation) GETSTRUCT(tup); |
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the |
||||
* command to have succeeded. This is for dump restoration purposes. |
||||
*/ |
||||
if (collForm->collowner != newOwnerId) |
||||
{ |
||||
AclResult aclresult; |
||||
|
||||
/* Superusers can always do it */ |
||||
if (!superuser()) |
||||
{ |
||||
/* Otherwise, must be owner of the existing object */ |
||||
if (!pg_collation_ownercheck(HeapTupleGetOid(tup), GetUserId())) |
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, |
||||
NameStr(collForm->collname)); |
||||
|
||||
/* Must be able to become new owner */ |
||||
check_is_member_of_role(GetUserId(), newOwnerId); |
||||
|
||||
/* New owner must have CREATE privilege on namespace */ |
||||
aclresult = pg_namespace_aclcheck(collForm->collnamespace, |
||||
newOwnerId, |
||||
ACL_CREATE); |
||||
if (aclresult != ACLCHECK_OK) |
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, |
||||
get_namespace_name(collForm->collnamespace)); |
||||
} |
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy |
||||
*/ |
||||
collForm->collowner = newOwnerId; |
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup); |
||||
|
||||
CatalogUpdateIndexes(rel, tup); |
||||
|
||||
/* Update owner dependency reference */ |
||||
changeDependencyOnOwner(CollationRelationId, collationOid, |
||||
newOwnerId); |
||||
} |
||||
|
||||
heap_freetuple(tup); |
||||
} |
||||
|
||||
/*
|
||||
* Execute ALTER COLLATION SET SCHEMA |
||||
*/ |
||||
void |
||||
AlterCollationNamespace(List *name, const char *newschema) |
||||
{ |
||||
Oid collOid, nspOid; |
||||
Relation rel; |
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
|
||||
collOid = get_collation_oid(name, false); |
||||
|
||||
/* get schema OID */ |
||||
nspOid = LookupCreationNamespace(newschema); |
||||
|
||||
AlterObjectNamespace(rel, COLLOID, -1, |
||||
collOid, nspOid, |
||||
Anum_pg_collation_collname, |
||||
Anum_pg_collation_collnamespace, |
||||
Anum_pg_collation_collowner, |
||||
ACL_KIND_COLLATION); |
||||
|
||||
heap_close(rel, NoLock); |
||||
} |
||||
|
||||
/*
|
||||
* Change collation schema, by oid |
||||
*/ |
||||
Oid |
||||
AlterCollationNamespace_oid(Oid collOid, Oid newNspOid) |
||||
{ |
||||
Oid oldNspOid; |
||||
Relation rel; |
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock); |
||||
|
||||
oldNspOid = AlterObjectNamespace(rel, COLLOID, -1, |
||||
collOid, newNspOid, |
||||
Anum_pg_collation_collname, |
||||
Anum_pg_collation_collnamespace, |
||||
Anum_pg_collation_collowner, |
||||
ACL_KIND_COLLATION); |
||||
|
||||
heap_close(rel, RowExclusiveLock); |
||||
|
||||
return oldNspOid; |
||||
} |
@ -0,0 +1,23 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_collation_fn.h |
||||
* prototypes for functions in catalog/pg_collation.c |
||||
* |
||||
* |
||||
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* src/include/catalog/pg_collation_fn.h |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef PG_COLLATION_FN_H |
||||
#define PG_COLLATION_FN_H |
||||
|
||||
extern Oid CollationCreate(const char *collname, Oid collnamespace, |
||||
Oid collowner, |
||||
int32 collencoding, |
||||
const char *collcollate, const char *collctype); |
||||
extern void RemoveCollationById(Oid collationOid); |
||||
|
||||
#endif /* PG_COLLATION_FN_H */ |
@ -0,0 +1,28 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* collationcmds.h |
||||
* prototypes for collationcmds.c. |
||||
* |
||||
* |
||||
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* src/include/commands/collationcmds.h |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#ifndef COLLATIONCMDS_H |
||||
#define COLLATIONCMDS_H |
||||
|
||||
#include "nodes/parsenodes.h" |
||||
|
||||
extern void DefineCollation(List *names, List *parameters); |
||||
extern void DropCollationsCommand(DropStmt *drop); |
||||
extern void RenameCollation(List *name, const char *newname); |
||||
extern void AlterCollationOwner(List *name, Oid newOwnerId); |
||||
extern void AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId); |
||||
extern void AlterCollationNamespace(List *name, const char *newschema); |
||||
extern Oid AlterCollationNamespace_oid(Oid collOid, Oid newNspOid); |
||||
|
||||
#endif /* COLLATIONCMDS_H */ |
Loading…
Reference in new issue