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:
Tom Lane 2011-03-11 13:20:11 -05:00
parent ac435a79c8
commit e3c732a85c
9 changed files with 158 additions and 84 deletions

View File

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

View File

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

View File

@ -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;
} }
/* /*

View File

@ -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);
} }

View File

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

View File

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

View File

@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201103101 #define CATALOG_VERSION_NO 201103111
#endif #endif

View File

@ -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 */

View File

@ -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%';