Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e3c732a

Browse files
committed
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.
1 parent ac435a7 commit e3c732a

File tree

9 files changed

+158
-84
lines changed

9 files changed

+158
-84
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,8 @@
21322132
<entry><structfield>collencoding</structfield></entry>
21332133
<entry><type>int4</type></entry>
21342134
<entry></entry>
2135-
<entry>Encoding to which the collation is applicable</entry>
2135+
<entry>Encoding in which the collation is applicable, or -1 if it
2136+
works for any encoding</entry>
21362137
</row>
21372138

21382139
<row>
@@ -2157,12 +2158,13 @@
21572158
<structfield>collencoding</>, <structfield>collnamespace</>) not just
21582159
(<structfield>collname</>, <structfield>collnamespace</>).
21592160
<productname>PostgreSQL</productname> generally ignores all
2160-
collations not belonging to the current database's encoding; therefore
2161-
it is sufficient to use a qualified SQL name
2161+
collations that do not have <structfield>collencoding</> equal to
2162+
either the current database's encoding or -1, and creation of new
2163+
entries matching an entry with <structfield>collencoding</> = -1
2164+
is forbidden. Therefore it is sufficient to use a qualified SQL name
21622165
(<replaceable>schema</>.<replaceable>name</>) to identify a collation,
21632166
even though this is not unique according to the catalog definition.
2164-
The current database's encoding is automatically used as an additional
2165-
lookup key. The reason for defining the catalog this way is that
2167+
The reason for defining the catalog this way is that
21662168
<application>initdb</> fills it in at cluster initialization time with
21672169
entries for all locales available on the system, so it must be able to
21682170
hold entries for all encodings that might ever be used in the cluster.

src/backend/catalog/information_schema.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ CREATE VIEW collations AS
448448
CAST('NO PAD' AS character_data) AS pad_attribute
449449
FROM pg_collation c, pg_namespace nc
450450
WHERE c.collnamespace = nc.oid
451-
AND collencoding = (SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database());
451+
AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database()));
452452

453453
GRANT SELECT ON collations TO PUBLIC;
454454

@@ -467,7 +467,7 @@ CREATE VIEW collation_character_set_applicability AS
467467
CAST(getdatabaseencoding() AS sql_identifier) AS character_set_name
468468
FROM pg_collation c, pg_namespace nc
469469
WHERE c.collnamespace = nc.oid
470-
AND collencoding = (SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database());
470+
AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database()));
471471

472472
GRANT SELECT ON collation_character_set_applicability TO PUBLIC;
473473

@@ -2036,7 +2036,7 @@ CREATE VIEW usage_privileges AS
20362036

20372037
WHERE u.oid = c.collowner
20382038
AND c.collnamespace = n.oid
2039-
AND c.collencoding = (SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())
2039+
AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database()))
20402040

20412041
UNION ALL
20422042

src/backend/catalog/namespace.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,27 +1617,35 @@ OpfamilyIsVisible(Oid opfid)
16171617
* CollationGetCollid
16181618
* Try to resolve an unqualified collation name.
16191619
* Returns OID if collation found in search path, else InvalidOid.
1620-
*
1621-
* This is essentially the same as RelnameGetRelid.
16221620
*/
16231621
Oid
16241622
CollationGetCollid(const char *collname)
16251623
{
1626-
Oid collid;
1624+
int32 dbencoding = GetDatabaseEncoding();
16271625
ListCell *l;
16281626

16291627
recomputeNamespacePath();
16301628

16311629
foreach(l, activeSearchPath)
16321630
{
16331631
Oid namespaceId = lfirst_oid(l);
1632+
Oid collid;
16341633

16351634
if (namespaceId == myTempNamespace)
16361635
continue; /* do not look in temp namespace */
16371636

1637+
/* Check for database-encoding-specific entry */
1638+
collid = GetSysCacheOid3(COLLNAMEENCNSP,
1639+
PointerGetDatum(collname),
1640+
Int32GetDatum(dbencoding),
1641+
ObjectIdGetDatum(namespaceId));
1642+
if (OidIsValid(collid))
1643+
return collid;
1644+
1645+
/* Check for any-encoding entry */
16381646
collid = GetSysCacheOid3(COLLNAMEENCNSP,
16391647
PointerGetDatum(collname),
1640-
Int32GetDatum(GetDatabaseEncoding()),
1648+
Int32GetDatum(-1),
16411649
ObjectIdGetDatum(namespaceId));
16421650
if (OidIsValid(collid))
16431651
return collid;
@@ -2901,12 +2909,10 @@ get_collation_oid(List *name, bool missing_ok)
29012909
{
29022910
char *schemaname;
29032911
char *collation_name;
2912+
int32 dbencoding = GetDatabaseEncoding();
29042913
Oid namespaceId;
2905-
Oid colloid = InvalidOid;
2914+
Oid colloid;
29062915
ListCell *l;
2907-
int encoding;
2908-
2909-
encoding = GetDatabaseEncoding();
29102916

29112917
/* deconstruct the name list */
29122918
DeconstructQualifiedName(name, &schemaname, &collation_name);
@@ -2915,10 +2921,20 @@ get_collation_oid(List *name, bool missing_ok)
29152921
{
29162922
/* use exact schema given */
29172923
namespaceId = LookupExplicitNamespace(schemaname);
2924+
2925+
/* first try for encoding-specific entry, then any-encoding */
29182926
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
29192927
PointerGetDatum(collation_name),
2920-
Int32GetDatum(encoding),
2928+
Int32GetDatum(dbencoding),
29212929
ObjectIdGetDatum(namespaceId));
2930+
if (OidIsValid(colloid))
2931+
return colloid;
2932+
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
2933+
PointerGetDatum(collation_name),
2934+
Int32GetDatum(-1),
2935+
ObjectIdGetDatum(namespaceId));
2936+
if (OidIsValid(colloid))
2937+
return colloid;
29222938
}
29232939
else
29242940
{
@@ -2934,20 +2950,26 @@ get_collation_oid(List *name, bool missing_ok)
29342950

29352951
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
29362952
PointerGetDatum(collation_name),
2937-
Int32GetDatum(encoding),
2953+
Int32GetDatum(dbencoding),
2954+
ObjectIdGetDatum(namespaceId));
2955+
if (OidIsValid(colloid))
2956+
return colloid;
2957+
colloid = GetSysCacheOid3(COLLNAMEENCNSP,
2958+
PointerGetDatum(collation_name),
2959+
Int32GetDatum(-1),
29382960
ObjectIdGetDatum(namespaceId));
29392961
if (OidIsValid(colloid))
29402962
return colloid;
29412963
}
29422964
}
29432965

29442966
/* Not found in path */
2945-
if (!OidIsValid(colloid) && !missing_ok)
2967+
if (!missing_ok)
29462968
ereport(ERROR,
29472969
(errcode(ERRCODE_UNDEFINED_OBJECT),
2948-
errmsg("collation \"%s\" for current database encoding \"%s\" does not exist",
2970+
errmsg("collation \"%s\" for encoding \"%s\" does not exist",
29492971
NameListToString(name), GetDatabaseEncodingName())));
2950-
return colloid;
2972+
return InvalidOid;
29512973
}
29522974

29532975
/*

src/backend/catalog/pg_collation.c

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
#include "postgres.h"
1616

17+
#include "access/genam.h"
1718
#include "access/heapam.h"
1819
#include "access/sysattr.h"
1920
#include "catalog/dependency.h"
@@ -22,16 +23,13 @@
2223
#include "catalog/pg_collation.h"
2324
#include "catalog/pg_collation_fn.h"
2425
#include "catalog/pg_namespace.h"
25-
#include "catalog/pg_proc.h"
2626
#include "mb/pg_wchar.h"
27-
#include "miscadmin.h"
28-
#include "utils/acl.h"
2927
#include "utils/builtins.h"
3028
#include "utils/fmgroids.h"
31-
#include "utils/rel.h"
3229
#include "utils/syscache.h"
3330
#include "utils/tqual.h"
3431

32+
3533
/*
3634
* CollationCreate
3735
*
@@ -43,12 +41,11 @@ CollationCreate(const char *collname, Oid collnamespace,
4341
int32 collencoding,
4442
const char *collcollate, const char *collctype)
4543
{
46-
int i;
4744
Relation rel;
4845
TupleDesc tupDesc;
4946
HeapTuple tup;
50-
bool nulls[Natts_pg_collation];
5147
Datum values[Natts_pg_collation];
48+
bool nulls[Natts_pg_collation];
5249
NameData name_name, name_collate, name_ctype;
5350
Oid oid;
5451
ObjectAddress myself,
@@ -60,7 +57,13 @@ CollationCreate(const char *collname, Oid collnamespace,
6057
AssertArg(collcollate);
6158
AssertArg(collctype);
6259

63-
/* make sure there is no existing collation of same name */
60+
/*
61+
* Make sure there is no existing collation of same name & encoding.
62+
*
63+
* This would be caught by the unique index anyway; we're just giving
64+
* a friendlier error message. The unique index provides a backstop
65+
* against race conditions.
66+
*/
6467
if (SearchSysCacheExists3(COLLNAMEENCNSP,
6568
PointerGetDatum(collname),
6669
Int32GetDatum(collencoding),
@@ -70,18 +73,27 @@ CollationCreate(const char *collname, Oid collnamespace,
7073
errmsg("collation \"%s\" for encoding \"%s\" already exists",
7174
collname, pg_encoding_to_char(collencoding))));
7275

76+
/*
77+
* Also forbid matching an any-encoding entry. This test of course is
78+
* not backed up by the unique index, but it's not a problem since we
79+
* don't support adding any-encoding entries after initdb.
80+
*/
81+
if (SearchSysCacheExists3(COLLNAMEENCNSP,
82+
PointerGetDatum(collname),
83+
Int32GetDatum(-1),
84+
ObjectIdGetDatum(collnamespace)))
85+
ereport(ERROR,
86+
(errcode(ERRCODE_DUPLICATE_OBJECT),
87+
errmsg("collation \"%s\" already exists",
88+
collname)));
89+
7390
/* open pg_collation */
7491
rel = heap_open(CollationRelationId, RowExclusiveLock);
75-
tupDesc = rel->rd_att;
76-
77-
/* initialize nulls and values */
78-
for (i = 0; i < Natts_pg_collation; i++)
79-
{
80-
nulls[i] = false;
81-
values[i] = (Datum) NULL;
82-
}
92+
tupDesc = RelationGetDescr(rel);
8393

8494
/* form a tuple */
95+
memset(nulls, 0, sizeof(nulls));
96+
8597
namestrcpy(&name_name, collname);
8698
values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name);
8799
values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace);
@@ -101,8 +113,9 @@ CollationCreate(const char *collname, Oid collnamespace,
101113
/* update the index if any */
102114
CatalogUpdateIndexes(rel, tup);
103115

116+
/* set up dependencies for the new collation */
104117
myself.classId = CollationRelationId;
105-
myself.objectId = HeapTupleGetOid(tup);
118+
myself.objectId = oid;
106119
myself.objectSubId = 0;
107120

108121
/* create dependency on namespace */
@@ -120,7 +133,7 @@ CollationCreate(const char *collname, Oid collnamespace,
120133

121134
/* Post creation hook for new collation */
122135
InvokeObjectAccessHook(OAT_POST_CREATE,
123-
CollationRelationId, HeapTupleGetOid(tup), 0);
136+
CollationRelationId, oid, 0);
124137

125138
heap_freetuple(tup);
126139
heap_close(rel, RowExclusiveLock);
@@ -138,26 +151,28 @@ void
138151
RemoveCollationById(Oid collationOid)
139152
{
140153
Relation rel;
141-
HeapTuple tuple;
142-
HeapScanDesc scan;
143154
ScanKeyData scanKeyData;
155+
SysScanDesc scandesc;
156+
HeapTuple tuple;
157+
158+
rel = heap_open(CollationRelationId, RowExclusiveLock);
144159

145160
ScanKeyInit(&scanKeyData,
146161
ObjectIdAttributeNumber,
147162
BTEqualStrategyNumber, F_OIDEQ,
148163
ObjectIdGetDatum(collationOid));
149164

150-
/* open pg_collation */
151-
rel = heap_open(CollationRelationId, RowExclusiveLock);
165+
scandesc = systable_beginscan(rel, CollationOidIndexId, true,
166+
SnapshotNow, 1, &scanKeyData);
152167

153-
scan = heap_beginscan(rel, SnapshotNow,
154-
1, &scanKeyData);
168+
tuple = systable_getnext(scandesc);
155169

156-
/* search for the target tuple */
157-
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
170+
if (HeapTupleIsValid(tuple))
158171
simple_heap_delete(rel, &tuple->t_self);
159172
else
160173
elog(ERROR, "could not find tuple for collation %u", collationOid);
161-
heap_endscan(scan);
174+
175+
systable_endscan(scandesc);
176+
162177
heap_close(rel, RowExclusiveLock);
163178
}

0 commit comments

Comments
 (0)