mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Create an explicit concept of collations that work for any encoding.
Use collencoding = -1 to represent such a collation in pg_collation. We need this to make the "default" entry work sanely, and a later patch will fix the C/POSIX entries to be represented this way instead of duplicating them across all encodings. All lookup operations now search first for an entry that's database-encoding-specific, and then for the same name with collencoding = -1. Also some incidental code cleanup in collationcmds.c and pg_collation.c.
This commit is contained in:
parent
ac435a79c8
commit
e3c732a85c
@ -2132,7 +2132,8 @@
|
|||||||
<entry><structfield>collencoding</structfield></entry>
|
<entry><structfield>collencoding</structfield></entry>
|
||||||
<entry><type>int4</type></entry>
|
<entry><type>int4</type></entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
<entry>Encoding to which the collation is applicable</entry>
|
<entry>Encoding in which the collation is applicable, or -1 if it
|
||||||
|
works for any encoding</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@ -2157,12 +2158,13 @@
|
|||||||
<structfield>collencoding</>, <structfield>collnamespace</>) not just
|
<structfield>collencoding</>, <structfield>collnamespace</>) not just
|
||||||
(<structfield>collname</>, <structfield>collnamespace</>).
|
(<structfield>collname</>, <structfield>collnamespace</>).
|
||||||
<productname>PostgreSQL</productname> generally ignores all
|
<productname>PostgreSQL</productname> generally ignores all
|
||||||
collations not belonging to the current database's encoding; therefore
|
collations that do not have <structfield>collencoding</> equal to
|
||||||
it is sufficient to use a qualified SQL name
|
either the current database's encoding or -1, and creation of new
|
||||||
|
entries matching an entry with <structfield>collencoding</> = -1
|
||||||
|
is forbidden. Therefore it is sufficient to use a qualified SQL name
|
||||||
(<replaceable>schema</>.<replaceable>name</>) to identify a collation,
|
(<replaceable>schema</>.<replaceable>name</>) to identify a collation,
|
||||||
even though this is not unique according to the catalog definition.
|
even though this is not unique according to the catalog definition.
|
||||||
The current database's encoding is automatically used as an additional
|
The reason for defining the catalog this way is that
|
||||||
lookup key. The reason for defining the catalog this way is that
|
|
||||||
<application>initdb</> fills it in at cluster initialization time with
|
<application>initdb</> fills it in at cluster initialization time with
|
||||||
entries for all locales available on the system, so it must be able to
|
entries for all locales available on the system, so it must be able to
|
||||||
hold entries for all encodings that might ever be used in the cluster.
|
hold entries for all encodings that might ever be used in the cluster.
|
||||||
|
@ -448,7 +448,7 @@ CREATE VIEW collations AS
|
|||||||
CAST('NO PAD' AS character_data) AS pad_attribute
|
CAST('NO PAD' AS character_data) AS pad_attribute
|
||||||
FROM pg_collation c, pg_namespace nc
|
FROM pg_collation c, pg_namespace nc
|
||||||
WHERE c.collnamespace = nc.oid
|
WHERE c.collnamespace = nc.oid
|
||||||
AND collencoding = (SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database());
|
AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database()));
|
||||||
|
|
||||||
GRANT SELECT ON collations TO PUBLIC;
|
GRANT SELECT ON collations TO PUBLIC;
|
||||||
|
|
||||||
@ -467,7 +467,7 @@ CREATE VIEW collation_character_set_applicability AS
|
|||||||
CAST(getdatabaseencoding() AS sql_identifier) AS character_set_name
|
CAST(getdatabaseencoding() AS sql_identifier) AS character_set_name
|
||||||
FROM pg_collation c, pg_namespace nc
|
FROM pg_collation c, pg_namespace nc
|
||||||
WHERE c.collnamespace = nc.oid
|
WHERE c.collnamespace = nc.oid
|
||||||
AND collencoding = (SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database());
|
AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database()));
|
||||||
|
|
||||||
GRANT SELECT ON collation_character_set_applicability TO PUBLIC;
|
GRANT SELECT ON collation_character_set_applicability TO PUBLIC;
|
||||||
|
|
||||||
@ -2036,7 +2036,7 @@ CREATE VIEW usage_privileges AS
|
|||||||
|
|
||||||
WHERE u.oid = c.collowner
|
WHERE u.oid = c.collowner
|
||||||
AND c.collnamespace = n.oid
|
AND c.collnamespace = n.oid
|
||||||
AND c.collencoding = (SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())
|
AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database()))
|
||||||
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
|
|
||||||
|
@ -1617,13 +1617,11 @@ OpfamilyIsVisible(Oid opfid)
|
|||||||
* CollationGetCollid
|
* CollationGetCollid
|
||||||
* Try to resolve an unqualified collation name.
|
* Try to resolve an unqualified collation name.
|
||||||
* Returns OID if collation found in search path, else InvalidOid.
|
* Returns OID if collation found in search path, else InvalidOid.
|
||||||
*
|
|
||||||
* This is essentially the same as RelnameGetRelid.
|
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
CollationGetCollid(const char *collname)
|
CollationGetCollid(const char *collname)
|
||||||
{
|
{
|
||||||
Oid collid;
|
int32 dbencoding = GetDatabaseEncoding();
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -1631,13 +1629,23 @@ CollationGetCollid(const char *collname)
|
|||||||
foreach(l, activeSearchPath)
|
foreach(l, activeSearchPath)
|
||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
Oid collid;
|
||||||
|
|
||||||
if (namespaceId == myTempNamespace)
|
if (namespaceId == myTempNamespace)
|
||||||
continue; /* do not look in temp namespace */
|
continue; /* do not look in temp namespace */
|
||||||
|
|
||||||
|
/* Check for database-encoding-specific entry */
|
||||||
collid = GetSysCacheOid3(COLLNAMEENCNSP,
|
collid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||||
PointerGetDatum(collname),
|
PointerGetDatum(collname),
|
||||||
Int32GetDatum(GetDatabaseEncoding()),
|
Int32GetDatum(dbencoding),
|
||||||
|
ObjectIdGetDatum(namespaceId));
|
||||||
|
if (OidIsValid(collid))
|
||||||
|
return collid;
|
||||||
|
|
||||||
|
/* Check for any-encoding entry */
|
||||||
|
collid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||||
|
PointerGetDatum(collname),
|
||||||
|
Int32GetDatum(-1),
|
||||||
ObjectIdGetDatum(namespaceId));
|
ObjectIdGetDatum(namespaceId));
|
||||||
if (OidIsValid(collid))
|
if (OidIsValid(collid))
|
||||||
return collid;
|
return collid;
|
||||||
@ -2901,12 +2909,10 @@ get_collation_oid(List *name, bool missing_ok)
|
|||||||
{
|
{
|
||||||
char *schemaname;
|
char *schemaname;
|
||||||
char *collation_name;
|
char *collation_name;
|
||||||
|
int32 dbencoding = GetDatabaseEncoding();
|
||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
Oid colloid = InvalidOid;
|
Oid colloid;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
int encoding;
|
|
||||||
|
|
||||||
encoding = GetDatabaseEncoding();
|
|
||||||
|
|
||||||
/* deconstruct the name list */
|
/* deconstruct the name list */
|
||||||
DeconstructQualifiedName(name, &schemaname, &collation_name);
|
DeconstructQualifiedName(name, &schemaname, &collation_name);
|
||||||
@ -2915,10 +2921,20 @@ get_collation_oid(List *name, bool missing_ok)
|
|||||||
{
|
{
|
||||||
/* use exact schema given */
|
/* use exact schema given */
|
||||||
namespaceId = LookupExplicitNamespace(schemaname);
|
namespaceId = LookupExplicitNamespace(schemaname);
|
||||||
|
|
||||||
|
/* first try for encoding-specific entry, then any-encoding */
|
||||||
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
|
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||||
PointerGetDatum(collation_name),
|
PointerGetDatum(collation_name),
|
||||||
Int32GetDatum(encoding),
|
Int32GetDatum(dbencoding),
|
||||||
ObjectIdGetDatum(namespaceId));
|
ObjectIdGetDatum(namespaceId));
|
||||||
|
if (OidIsValid(colloid))
|
||||||
|
return colloid;
|
||||||
|
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||||
|
PointerGetDatum(collation_name),
|
||||||
|
Int32GetDatum(-1),
|
||||||
|
ObjectIdGetDatum(namespaceId));
|
||||||
|
if (OidIsValid(colloid))
|
||||||
|
return colloid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2934,7 +2950,13 @@ get_collation_oid(List *name, bool missing_ok)
|
|||||||
|
|
||||||
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
|
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||||
PointerGetDatum(collation_name),
|
PointerGetDatum(collation_name),
|
||||||
Int32GetDatum(encoding),
|
Int32GetDatum(dbencoding),
|
||||||
|
ObjectIdGetDatum(namespaceId));
|
||||||
|
if (OidIsValid(colloid))
|
||||||
|
return colloid;
|
||||||
|
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
|
||||||
|
PointerGetDatum(collation_name),
|
||||||
|
Int32GetDatum(-1),
|
||||||
ObjectIdGetDatum(namespaceId));
|
ObjectIdGetDatum(namespaceId));
|
||||||
if (OidIsValid(colloid))
|
if (OidIsValid(colloid))
|
||||||
return colloid;
|
return colloid;
|
||||||
@ -2942,12 +2964,12 @@ get_collation_oid(List *name, bool missing_ok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not found in path */
|
/* Not found in path */
|
||||||
if (!OidIsValid(colloid) && !missing_ok)
|
if (!missing_ok)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
errmsg("collation \"%s\" for current database encoding \"%s\" does not exist",
|
errmsg("collation \"%s\" for encoding \"%s\" does not exist",
|
||||||
NameListToString(name), GetDatabaseEncodingName())));
|
NameListToString(name), GetDatabaseEncodingName())));
|
||||||
return colloid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
@ -22,16 +23,13 @@
|
|||||||
#include "catalog/pg_collation.h"
|
#include "catalog/pg_collation.h"
|
||||||
#include "catalog/pg_collation_fn.h"
|
#include "catalog/pg_collation_fn.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
#include "catalog/pg_proc.h"
|
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "utils/acl.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/rel.h"
|
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/tqual.h"
|
#include "utils/tqual.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CollationCreate
|
* CollationCreate
|
||||||
*
|
*
|
||||||
@ -43,12 +41,11 @@ CollationCreate(const char *collname, Oid collnamespace,
|
|||||||
int32 collencoding,
|
int32 collencoding,
|
||||||
const char *collcollate, const char *collctype)
|
const char *collcollate, const char *collctype)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Relation rel;
|
Relation rel;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
bool nulls[Natts_pg_collation];
|
|
||||||
Datum values[Natts_pg_collation];
|
Datum values[Natts_pg_collation];
|
||||||
|
bool nulls[Natts_pg_collation];
|
||||||
NameData name_name, name_collate, name_ctype;
|
NameData name_name, name_collate, name_ctype;
|
||||||
Oid oid;
|
Oid oid;
|
||||||
ObjectAddress myself,
|
ObjectAddress myself,
|
||||||
@ -60,7 +57,13 @@ CollationCreate(const char *collname, Oid collnamespace,
|
|||||||
AssertArg(collcollate);
|
AssertArg(collcollate);
|
||||||
AssertArg(collctype);
|
AssertArg(collctype);
|
||||||
|
|
||||||
/* make sure there is no existing collation of same name */
|
/*
|
||||||
|
* Make sure there is no existing collation of same name & encoding.
|
||||||
|
*
|
||||||
|
* This would be caught by the unique index anyway; we're just giving
|
||||||
|
* a friendlier error message. The unique index provides a backstop
|
||||||
|
* against race conditions.
|
||||||
|
*/
|
||||||
if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||||
PointerGetDatum(collname),
|
PointerGetDatum(collname),
|
||||||
Int32GetDatum(collencoding),
|
Int32GetDatum(collencoding),
|
||||||
@ -70,18 +73,27 @@ CollationCreate(const char *collname, Oid collnamespace,
|
|||||||
errmsg("collation \"%s\" for encoding \"%s\" already exists",
|
errmsg("collation \"%s\" for encoding \"%s\" already exists",
|
||||||
collname, pg_encoding_to_char(collencoding))));
|
collname, pg_encoding_to_char(collencoding))));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Also forbid matching an any-encoding entry. This test of course is
|
||||||
|
* not backed up by the unique index, but it's not a problem since we
|
||||||
|
* don't support adding any-encoding entries after initdb.
|
||||||
|
*/
|
||||||
|
if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||||
|
PointerGetDatum(collname),
|
||||||
|
Int32GetDatum(-1),
|
||||||
|
ObjectIdGetDatum(collnamespace)))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||||
|
errmsg("collation \"%s\" already exists",
|
||||||
|
collname)));
|
||||||
|
|
||||||
/* open pg_collation */
|
/* open pg_collation */
|
||||||
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
||||||
tupDesc = rel->rd_att;
|
tupDesc = RelationGetDescr(rel);
|
||||||
|
|
||||||
/* initialize nulls and values */
|
|
||||||
for (i = 0; i < Natts_pg_collation; i++)
|
|
||||||
{
|
|
||||||
nulls[i] = false;
|
|
||||||
values[i] = (Datum) NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* form a tuple */
|
/* form a tuple */
|
||||||
|
memset(nulls, 0, sizeof(nulls));
|
||||||
|
|
||||||
namestrcpy(&name_name, collname);
|
namestrcpy(&name_name, collname);
|
||||||
values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name);
|
values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name);
|
||||||
values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace);
|
values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace);
|
||||||
@ -101,8 +113,9 @@ CollationCreate(const char *collname, Oid collnamespace,
|
|||||||
/* update the index if any */
|
/* update the index if any */
|
||||||
CatalogUpdateIndexes(rel, tup);
|
CatalogUpdateIndexes(rel, tup);
|
||||||
|
|
||||||
|
/* set up dependencies for the new collation */
|
||||||
myself.classId = CollationRelationId;
|
myself.classId = CollationRelationId;
|
||||||
myself.objectId = HeapTupleGetOid(tup);
|
myself.objectId = oid;
|
||||||
myself.objectSubId = 0;
|
myself.objectSubId = 0;
|
||||||
|
|
||||||
/* create dependency on namespace */
|
/* create dependency on namespace */
|
||||||
@ -120,7 +133,7 @@ CollationCreate(const char *collname, Oid collnamespace,
|
|||||||
|
|
||||||
/* Post creation hook for new collation */
|
/* Post creation hook for new collation */
|
||||||
InvokeObjectAccessHook(OAT_POST_CREATE,
|
InvokeObjectAccessHook(OAT_POST_CREATE,
|
||||||
CollationRelationId, HeapTupleGetOid(tup), 0);
|
CollationRelationId, oid, 0);
|
||||||
|
|
||||||
heap_freetuple(tup);
|
heap_freetuple(tup);
|
||||||
heap_close(rel, RowExclusiveLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
@ -138,26 +151,28 @@ void
|
|||||||
RemoveCollationById(Oid collationOid)
|
RemoveCollationById(Oid collationOid)
|
||||||
{
|
{
|
||||||
Relation rel;
|
Relation rel;
|
||||||
HeapTuple tuple;
|
|
||||||
HeapScanDesc scan;
|
|
||||||
ScanKeyData scanKeyData;
|
ScanKeyData scanKeyData;
|
||||||
|
SysScanDesc scandesc;
|
||||||
|
HeapTuple tuple;
|
||||||
|
|
||||||
|
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
ScanKeyInit(&scanKeyData,
|
ScanKeyInit(&scanKeyData,
|
||||||
ObjectIdAttributeNumber,
|
ObjectIdAttributeNumber,
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
ObjectIdGetDatum(collationOid));
|
ObjectIdGetDatum(collationOid));
|
||||||
|
|
||||||
/* open pg_collation */
|
scandesc = systable_beginscan(rel, CollationOidIndexId, true,
|
||||||
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
SnapshotNow, 1, &scanKeyData);
|
||||||
|
|
||||||
scan = heap_beginscan(rel, SnapshotNow,
|
tuple = systable_getnext(scandesc);
|
||||||
1, &scanKeyData);
|
|
||||||
|
|
||||||
/* search for the target tuple */
|
if (HeapTupleIsValid(tuple))
|
||||||
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
|
|
||||||
simple_heap_delete(rel, &tuple->t_self);
|
simple_heap_delete(rel, &tuple->t_self);
|
||||||
else
|
else
|
||||||
elog(ERROR, "could not find tuple for collation %u", collationOid);
|
elog(ERROR, "could not find tuple for collation %u", collationOid);
|
||||||
heap_endscan(scan);
|
|
||||||
|
systable_endscan(scandesc);
|
||||||
|
|
||||||
heap_close(rel, RowExclusiveLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* collationcmds.c
|
* collationcmds.c
|
||||||
* collation creation command support code
|
* collation-related commands support code
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
@ -27,7 +27,6 @@
|
|||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "parser/parse_type.h"
|
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
@ -134,11 +133,11 @@ DefineCollation(List *names, List *parameters)
|
|||||||
check_encoding_locale_matches(GetDatabaseEncoding(), collcollate, collctype);
|
check_encoding_locale_matches(GetDatabaseEncoding(), collcollate, collctype);
|
||||||
|
|
||||||
newoid = CollationCreate(collName,
|
newoid = CollationCreate(collName,
|
||||||
collNamespace,
|
collNamespace,
|
||||||
GetUserId(),
|
GetUserId(),
|
||||||
GetDatabaseEncoding(),
|
GetDatabaseEncoding(),
|
||||||
collcollate,
|
collcollate,
|
||||||
collctype);
|
collctype);
|
||||||
|
|
||||||
/* check that the locales can be loaded */
|
/* check that the locales can be loaded */
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
@ -235,11 +234,22 @@ RenameCollation(List *name, const char *newname)
|
|||||||
ObjectIdGetDatum(namespaceOid)))
|
ObjectIdGetDatum(namespaceOid)))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||||
errmsg("collation \"%s\" for current database encoding \"%s\" already exists in schema \"%s\"",
|
errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
|
||||||
newname,
|
newname,
|
||||||
GetDatabaseEncodingName(),
|
GetDatabaseEncodingName(),
|
||||||
get_namespace_name(namespaceOid))));
|
get_namespace_name(namespaceOid))));
|
||||||
|
|
||||||
|
/* mustn't match an any-encoding entry, either */
|
||||||
|
if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||||
|
CStringGetDatum(newname),
|
||||||
|
Int32GetDatum(-1),
|
||||||
|
ObjectIdGetDatum(namespaceOid)))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||||
|
errmsg("collation \"%s\" already exists in schema \"%s\"",
|
||||||
|
newname,
|
||||||
|
get_namespace_name(namespaceOid))));
|
||||||
|
|
||||||
/* must be owner */
|
/* must be owner */
|
||||||
if (!pg_collation_ownercheck(collationOid, GetUserId()))
|
if (!pg_collation_ownercheck(collationOid, GetUserId()))
|
||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
|
||||||
@ -256,8 +266,9 @@ RenameCollation(List *name, const char *newname)
|
|||||||
simple_heap_update(rel, &tup->t_self, tup);
|
simple_heap_update(rel, &tup->t_self, tup);
|
||||||
CatalogUpdateIndexes(rel, tup);
|
CatalogUpdateIndexes(rel, tup);
|
||||||
|
|
||||||
heap_close(rel, NoLock);
|
|
||||||
heap_freetuple(tup);
|
heap_freetuple(tup);
|
||||||
|
|
||||||
|
heap_close(rel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -275,7 +286,7 @@ AlterCollationOwner(List *name, Oid newOwnerId)
|
|||||||
|
|
||||||
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
|
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
|
||||||
|
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -290,7 +301,7 @@ AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId)
|
|||||||
|
|
||||||
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
|
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
|
||||||
|
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -364,24 +375,14 @@ AlterCollationOwner_internal(Relation rel, Oid collationOid, Oid newOwnerId)
|
|||||||
void
|
void
|
||||||
AlterCollationNamespace(List *name, const char *newschema)
|
AlterCollationNamespace(List *name, const char *newschema)
|
||||||
{
|
{
|
||||||
Oid collOid, nspOid;
|
Oid collOid,
|
||||||
Relation rel;
|
nspOid;
|
||||||
|
|
||||||
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
|
||||||
|
|
||||||
collOid = get_collation_oid(name, false);
|
collOid = get_collation_oid(name, false);
|
||||||
|
|
||||||
/* get schema OID */
|
|
||||||
nspOid = LookupCreationNamespace(newschema);
|
nspOid = LookupCreationNamespace(newschema);
|
||||||
|
|
||||||
AlterObjectNamespace(rel, COLLOID, -1,
|
AlterCollationNamespace_oid(collOid, nspOid);
|
||||||
collOid, nspOid,
|
|
||||||
Anum_pg_collation_collname,
|
|
||||||
Anum_pg_collation_collnamespace,
|
|
||||||
Anum_pg_collation_collowner,
|
|
||||||
ACL_KIND_COLLATION);
|
|
||||||
|
|
||||||
heap_close(rel, NoLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -392,9 +393,43 @@ AlterCollationNamespace_oid(Oid collOid, Oid newNspOid)
|
|||||||
{
|
{
|
||||||
Oid oldNspOid;
|
Oid oldNspOid;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
|
char *collation_name;
|
||||||
|
|
||||||
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to check for name collision ourselves, because
|
||||||
|
* AlterObjectNamespace doesn't know how to deal with the encoding
|
||||||
|
* considerations.
|
||||||
|
*/
|
||||||
|
collation_name = get_collation_name(collOid);
|
||||||
|
if (!collation_name)
|
||||||
|
elog(ERROR, "cache lookup failed for collation %u", collOid);
|
||||||
|
|
||||||
|
/* make sure the name doesn't already exist in new schema */
|
||||||
|
if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||||
|
CStringGetDatum(collation_name),
|
||||||
|
Int32GetDatum(GetDatabaseEncoding()),
|
||||||
|
ObjectIdGetDatum(newNspOid)))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||||
|
errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
|
||||||
|
collation_name,
|
||||||
|
GetDatabaseEncodingName(),
|
||||||
|
get_namespace_name(newNspOid))));
|
||||||
|
|
||||||
|
/* mustn't match an any-encoding entry, either */
|
||||||
|
if (SearchSysCacheExists3(COLLNAMEENCNSP,
|
||||||
|
CStringGetDatum(collation_name),
|
||||||
|
Int32GetDatum(-1),
|
||||||
|
ObjectIdGetDatum(newNspOid)))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||||
|
errmsg("collation \"%s\" already exists in schema \"%s\"",
|
||||||
|
collation_name,
|
||||||
|
get_namespace_name(newNspOid))));
|
||||||
|
|
||||||
|
/* OK, do the work */
|
||||||
oldNspOid = AlterObjectNamespace(rel, COLLOID, -1,
|
oldNspOid = AlterObjectNamespace(rel, COLLOID, -1,
|
||||||
collOid, newNspOid,
|
collOid, newNspOid,
|
||||||
Anum_pg_collation_collname,
|
Anum_pg_collation_collname,
|
||||||
|
@ -609,7 +609,7 @@ static const pgsql_thing_t words_after_create[] = {
|
|||||||
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
|
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
|
||||||
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
|
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
|
||||||
* skip it */
|
* skip it */
|
||||||
{"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding = pg_char_to_encoding(getdatabaseencoding()) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
|
{"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
|
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201103101
|
#define CATALOG_VERSION_NO 201103111
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,9 +32,9 @@
|
|||||||
CATALOG(pg_collation,3456)
|
CATALOG(pg_collation,3456)
|
||||||
{
|
{
|
||||||
NameData collname; /* collation name */
|
NameData collname; /* collation name */
|
||||||
Oid collnamespace; /* OID of namespace containing this collation */
|
Oid collnamespace; /* OID of namespace containing collation */
|
||||||
Oid collowner;
|
Oid collowner; /* owner of collation */
|
||||||
int4 collencoding; /* encoding that this collation applies to */
|
int4 collencoding; /* encoding for this collation; -1 = "all" */
|
||||||
NameData collcollate; /* LC_COLLATE setting */
|
NameData collcollate; /* LC_COLLATE setting */
|
||||||
NameData collctype; /* LC_CTYPE setting */
|
NameData collctype; /* LC_CTYPE setting */
|
||||||
} FormData_pg_collation;
|
} FormData_pg_collation;
|
||||||
@ -58,8 +58,8 @@ typedef FormData_pg_collation *Form_pg_collation;
|
|||||||
#define Anum_pg_collation_collcollate 5
|
#define Anum_pg_collation_collcollate 5
|
||||||
#define Anum_pg_collation_collctype 6
|
#define Anum_pg_collation_collctype 6
|
||||||
|
|
||||||
DATA(insert OID = 100 ( default PGNSP PGUID 0 "" "" ));
|
DATA(insert OID = 100 ( default PGNSP PGUID -1 "" "" ));
|
||||||
DESCR("placeholder for default collation");
|
DESCR("database's default collation");
|
||||||
#define DEFAULT_COLLATION_OID 100
|
#define DEFAULT_COLLATION_OID 100
|
||||||
|
|
||||||
#endif /* PG_COLLATION_H */
|
#endif /* PG_COLLATION_H */
|
||||||
|
@ -18,14 +18,14 @@ CREATE TABLE collate_test_fail (
|
|||||||
a int,
|
a int,
|
||||||
b text COLLATE "ja_JP.eucjp"
|
b text COLLATE "ja_JP.eucjp"
|
||||||
);
|
);
|
||||||
ERROR: collation "ja_JP.eucjp" for current database encoding "UTF8" does not exist
|
ERROR: collation "ja_JP.eucjp" for encoding "UTF8" does not exist
|
||||||
LINE 3: b text COLLATE "ja_JP.eucjp"
|
LINE 3: b text COLLATE "ja_JP.eucjp"
|
||||||
^
|
^
|
||||||
CREATE TABLE collate_test_fail (
|
CREATE TABLE collate_test_fail (
|
||||||
a int,
|
a int,
|
||||||
b text COLLATE "foo"
|
b text COLLATE "foo"
|
||||||
);
|
);
|
||||||
ERROR: collation "foo" for current database encoding "UTF8" does not exist
|
ERROR: collation "foo" for encoding "UTF8" does not exist
|
||||||
LINE 3: b text COLLATE "foo"
|
LINE 3: b text COLLATE "foo"
|
||||||
^
|
^
|
||||||
CREATE TABLE collate_test_fail (
|
CREATE TABLE collate_test_fail (
|
||||||
@ -752,7 +752,7 @@ ERROR: parameter "lc_ctype" must be specified
|
|||||||
CREATE COLLATION testx (locale = 'nonsense'); -- fail
|
CREATE COLLATION testx (locale = 'nonsense'); -- fail
|
||||||
ERROR: could not create locale "nonsense": No such file or directory
|
ERROR: could not create locale "nonsense": No such file or directory
|
||||||
CREATE COLLATION test4 FROM nonsense;
|
CREATE COLLATION test4 FROM nonsense;
|
||||||
ERROR: collation "nonsense" for current database encoding "UTF8" does not exist
|
ERROR: collation "nonsense" for encoding "UTF8" does not exist
|
||||||
CREATE COLLATION test5 FROM test0;
|
CREATE COLLATION test5 FROM test0;
|
||||||
SELECT collname, collencoding, collcollate, collctype FROM pg_collation WHERE collname LIKE 'test%' ORDER BY 1;
|
SELECT collname, collencoding, collcollate, collctype FROM pg_collation WHERE collname LIKE 'test%' ORDER BY 1;
|
||||||
collname | collencoding | collcollate | collctype
|
collname | collencoding | collcollate | collctype
|
||||||
@ -764,9 +764,9 @@ SELECT collname, collencoding, collcollate, collctype FROM pg_collation WHERE co
|
|||||||
|
|
||||||
ALTER COLLATION test1 RENAME TO test11;
|
ALTER COLLATION test1 RENAME TO test11;
|
||||||
ALTER COLLATION test0 RENAME TO test11; -- fail
|
ALTER COLLATION test0 RENAME TO test11; -- fail
|
||||||
ERROR: collation "test11" for current database encoding "UTF8" already exists in schema "public"
|
ERROR: collation "test11" for encoding "UTF8" already exists in schema "public"
|
||||||
ALTER COLLATION test1 RENAME TO test22; -- fail
|
ALTER COLLATION test1 RENAME TO test22; -- fail
|
||||||
ERROR: collation "test1" for current database encoding "UTF8" does not exist
|
ERROR: collation "test1" for encoding "UTF8" does not exist
|
||||||
ALTER COLLATION test11 OWNER TO regress_test_role;
|
ALTER COLLATION test11 OWNER TO regress_test_role;
|
||||||
ALTER COLLATION test11 OWNER TO nonsense;
|
ALTER COLLATION test11 OWNER TO nonsense;
|
||||||
ERROR: role "nonsense" does not exist
|
ERROR: role "nonsense" does not exist
|
||||||
@ -785,7 +785,7 @@ SELECT collname, nspname, obj_description(pg_collation.oid, 'pg_collation')
|
|||||||
|
|
||||||
DROP COLLATION test0, test_schema.test11, test5;
|
DROP COLLATION test0, test_schema.test11, test5;
|
||||||
DROP COLLATION test0; -- fail
|
DROP COLLATION test0; -- fail
|
||||||
ERROR: collation "test0" for current database encoding "UTF8" does not exist
|
ERROR: collation "test0" for encoding "UTF8" does not exist
|
||||||
DROP COLLATION IF EXISTS test0;
|
DROP COLLATION IF EXISTS test0;
|
||||||
NOTICE: collation "test0" does not exist, skipping
|
NOTICE: collation "test0" does not exist, skipping
|
||||||
SELECT collname FROM pg_collation WHERE collname LIKE 'test%';
|
SELECT collname FROM pg_collation WHERE collname LIKE 'test%';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user