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