Skip to content

Commit 3aa2373

Browse files
committed
Refactor the code to create a pg_locale_t into new function.
Reviewed-by: Andreas Karlsson Discussion: https://postgr.es/m/59da7ee4-5e1a-4727-b464-a603c6ed84cd@proxel.se
1 parent 924e039 commit 3aa2373

File tree

1 file changed

+139
-157
lines changed

1 file changed

+139
-157
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 139 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,42 +1215,135 @@ IsoLocaleName(const char *winlocname)
12151215

12161216

12171217
/*
1218-
* Cache mechanism for collation information.
1219-
*
1220-
* Note that we currently lack any way to flush the cache. Since we don't
1221-
* support ALTER COLLATION, this is OK. The worst case is that someone
1222-
* drops a collation, and a useless cache entry hangs around in existing
1223-
* backends.
1218+
* Create a new pg_locale_t struct for the given collation oid.
12241219
*/
1225-
static collation_cache_entry *
1226-
lookup_collation_cache(Oid collation)
1220+
static pg_locale_t
1221+
create_pg_locale(Oid collid, MemoryContext context)
12271222
{
1228-
collation_cache_entry *cache_entry;
1229-
bool found;
1223+
HeapTuple tp;
1224+
Form_pg_collation collform;
1225+
pg_locale_t result;
1226+
Datum datum;
1227+
bool isnull;
12301228

1231-
Assert(OidIsValid(collation));
1232-
Assert(collation != DEFAULT_COLLATION_OID);
1229+
result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
12331230

1234-
if (CollationCache == NULL)
1231+
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
1232+
if (!HeapTupleIsValid(tp))
1233+
elog(ERROR, "cache lookup failed for collation %u", collid);
1234+
collform = (Form_pg_collation) GETSTRUCT(tp);
1235+
1236+
result->provider = collform->collprovider;
1237+
result->deterministic = collform->collisdeterministic;
1238+
1239+
if (collform->collprovider == COLLPROVIDER_BUILTIN)
12351240
{
1236-
CollationCacheContext = AllocSetContextCreate(TopMemoryContext,
1237-
"collation cache",
1238-
ALLOCSET_DEFAULT_SIZES);
1239-
CollationCache = collation_cache_create(CollationCacheContext,
1240-
16, NULL);
1241+
const char *locstr;
1242+
1243+
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
1244+
locstr = TextDatumGetCString(datum);
1245+
1246+
result->collate_is_c = true;
1247+
result->ctype_is_c = (strcmp(locstr, "C") == 0);
1248+
1249+
builtin_validate_locale(GetDatabaseEncoding(), locstr);
1250+
1251+
result->info.builtin.locale = MemoryContextStrdup(context,
1252+
locstr);
12411253
}
1254+
else if (collform->collprovider == COLLPROVIDER_ICU)
1255+
{
1256+
#ifdef USE_ICU
1257+
const char *iculocstr;
1258+
const char *icurules;
12421259

1243-
cache_entry = collation_cache_insert(CollationCache, collation, &found);
1244-
if (!found)
1260+
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
1261+
iculocstr = TextDatumGetCString(datum);
1262+
1263+
result->collate_is_c = false;
1264+
result->ctype_is_c = false;
1265+
1266+
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
1267+
if (!isnull)
1268+
icurules = TextDatumGetCString(datum);
1269+
else
1270+
icurules = NULL;
1271+
1272+
result->info.icu.locale = MemoryContextStrdup(context, iculocstr);
1273+
result->info.icu.ucol = make_icu_collator(iculocstr, icurules);
1274+
#else
1275+
/* could get here if a collation was created by a build with ICU */
1276+
ereport(ERROR,
1277+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1278+
errmsg("ICU is not supported in this build")));
1279+
#endif
1280+
}
1281+
else if (collform->collprovider == COLLPROVIDER_LIBC)
12451282
{
1246-
/*
1247-
* Make sure cache entry is marked invalid, in case we fail before
1248-
* setting things.
1249-
*/
1250-
cache_entry->locale = 0;
1283+
const char *collcollate;
1284+
const char *collctype;
1285+
1286+
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collcollate);
1287+
collcollate = TextDatumGetCString(datum);
1288+
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collctype);
1289+
collctype = TextDatumGetCString(datum);
1290+
1291+
result->collate_is_c = (strcmp(collcollate, "C") == 0) ||
1292+
(strcmp(collcollate, "POSIX") == 0);
1293+
result->ctype_is_c = (strcmp(collctype, "C") == 0) ||
1294+
(strcmp(collctype, "POSIX") == 0);
1295+
1296+
result->info.lt = make_libc_collator(collcollate, collctype);
1297+
}
1298+
else
1299+
/* shouldn't happen */
1300+
PGLOCALE_SUPPORT_ERROR(collform->collprovider);
1301+
1302+
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
1303+
&isnull);
1304+
if (!isnull)
1305+
{
1306+
char *actual_versionstr;
1307+
char *collversionstr;
1308+
1309+
collversionstr = TextDatumGetCString(datum);
1310+
1311+
if (collform->collprovider == COLLPROVIDER_LIBC)
1312+
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collcollate);
1313+
else
1314+
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
1315+
1316+
actual_versionstr = get_collation_actual_version(collform->collprovider,
1317+
TextDatumGetCString(datum));
1318+
if (!actual_versionstr)
1319+
{
1320+
/*
1321+
* This could happen when specifying a version in CREATE COLLATION
1322+
* but the provider does not support versioning, or manually
1323+
* creating a mess in the catalogs.
1324+
*/
1325+
ereport(ERROR,
1326+
(errmsg("collation \"%s\" has no actual version, but a version was recorded",
1327+
NameStr(collform->collname))));
1328+
}
1329+
1330+
if (strcmp(actual_versionstr, collversionstr) != 0)
1331+
ereport(WARNING,
1332+
(errmsg("collation \"%s\" has version mismatch",
1333+
NameStr(collform->collname)),
1334+
errdetail("The collation in the database was created using version %s, "
1335+
"but the operating system provides version %s.",
1336+
collversionstr, actual_versionstr),
1337+
errhint("Rebuild all objects affected by this collation and run "
1338+
"ALTER COLLATION %s REFRESH VERSION, "
1339+
"or build PostgreSQL with the right library version.",
1340+
quote_qualified_identifier(get_namespace_name(collform->collnamespace),
1341+
NameStr(collform->collname)))));
12511342
}
12521343

1253-
return cache_entry;
1344+
ReleaseSysCache(tp);
1345+
1346+
return result;
12541347
}
12551348

12561349
/*
@@ -1358,6 +1451,7 @@ pg_locale_t
13581451
pg_newlocale_from_collation(Oid collid)
13591452
{
13601453
collation_cache_entry *cache_entry;
1454+
bool found;
13611455

13621456
if (collid == DEFAULT_COLLATION_OID)
13631457
return &default_locale;
@@ -1368,140 +1462,28 @@ pg_newlocale_from_collation(Oid collid)
13681462
if (last_collation_cache_oid == collid)
13691463
return last_collation_cache_locale;
13701464

1371-
cache_entry = lookup_collation_cache(collid);
1372-
1373-
if (cache_entry->locale == 0)
1465+
if (CollationCache == NULL)
13741466
{
1375-
/* We haven't computed this yet in this session, so do it */
1376-
HeapTuple tp;
1377-
Form_pg_collation collform;
1378-
struct pg_locale_struct result;
1379-
pg_locale_t resultp;
1380-
Datum datum;
1381-
bool isnull;
1382-
1383-
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
1384-
if (!HeapTupleIsValid(tp))
1385-
elog(ERROR, "cache lookup failed for collation %u", collid);
1386-
collform = (Form_pg_collation) GETSTRUCT(tp);
1387-
1388-
/* We'll fill in the result struct locally before allocating memory */
1389-
memset(&result, 0, sizeof(result));
1390-
result.provider = collform->collprovider;
1391-
result.deterministic = collform->collisdeterministic;
1392-
1393-
if (collform->collprovider == COLLPROVIDER_BUILTIN)
1394-
{
1395-
const char *locstr;
1396-
1397-
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
1398-
locstr = TextDatumGetCString(datum);
1399-
1400-
result.collate_is_c = true;
1401-
result.ctype_is_c = (strcmp(locstr, "C") == 0);
1402-
1403-
builtin_validate_locale(GetDatabaseEncoding(), locstr);
1404-
1405-
result.info.builtin.locale = MemoryContextStrdup(TopMemoryContext,
1406-
locstr);
1407-
}
1408-
else if (collform->collprovider == COLLPROVIDER_ICU)
1409-
{
1410-
#ifdef USE_ICU
1411-
const char *iculocstr;
1412-
const char *icurules;
1413-
1414-
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
1415-
iculocstr = TextDatumGetCString(datum);
1416-
1417-
result.collate_is_c = false;
1418-
result.ctype_is_c = false;
1419-
1420-
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
1421-
if (!isnull)
1422-
icurules = TextDatumGetCString(datum);
1423-
else
1424-
icurules = NULL;
1425-
1426-
result.info.icu.locale = MemoryContextStrdup(TopMemoryContext, iculocstr);
1427-
result.info.icu.ucol = make_icu_collator(iculocstr, icurules);
1428-
#else
1429-
/* could get here if a collation was created by a build with ICU */
1430-
ereport(ERROR,
1431-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1432-
errmsg("ICU is not supported in this build")));
1433-
#endif
1434-
}
1435-
else if (collform->collprovider == COLLPROVIDER_LIBC)
1436-
{
1437-
const char *collcollate;
1438-
const char *collctype;
1439-
1440-
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collcollate);
1441-
collcollate = TextDatumGetCString(datum);
1442-
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collctype);
1443-
collctype = TextDatumGetCString(datum);
1444-
1445-
result.collate_is_c = (strcmp(collcollate, "C") == 0) ||
1446-
(strcmp(collcollate, "POSIX") == 0);
1447-
result.ctype_is_c = (strcmp(collctype, "C") == 0) ||
1448-
(strcmp(collctype, "POSIX") == 0);
1449-
1450-
result.info.lt = make_libc_collator(collcollate, collctype);
1451-
}
1452-
else
1453-
/* shouldn't happen */
1454-
PGLOCALE_SUPPORT_ERROR(collform->collprovider);
1455-
1456-
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
1457-
&isnull);
1458-
if (!isnull)
1459-
{
1460-
char *actual_versionstr;
1461-
char *collversionstr;
1462-
1463-
collversionstr = TextDatumGetCString(datum);
1464-
1465-
if (collform->collprovider == COLLPROVIDER_LIBC)
1466-
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_collcollate);
1467-
else
1468-
datum = SysCacheGetAttrNotNull(COLLOID, tp, Anum_pg_collation_colllocale);
1469-
1470-
actual_versionstr = get_collation_actual_version(collform->collprovider,
1471-
TextDatumGetCString(datum));
1472-
if (!actual_versionstr)
1473-
{
1474-
/*
1475-
* This could happen when specifying a version in CREATE
1476-
* COLLATION but the provider does not support versioning, or
1477-
* manually creating a mess in the catalogs.
1478-
*/
1479-
ereport(ERROR,
1480-
(errmsg("collation \"%s\" has no actual version, but a version was recorded",
1481-
NameStr(collform->collname))));
1482-
}
1483-
1484-
if (strcmp(actual_versionstr, collversionstr) != 0)
1485-
ereport(WARNING,
1486-
(errmsg("collation \"%s\" has version mismatch",
1487-
NameStr(collform->collname)),
1488-
errdetail("The collation in the database was created using version %s, "
1489-
"but the operating system provides version %s.",
1490-
collversionstr, actual_versionstr),
1491-
errhint("Rebuild all objects affected by this collation and run "
1492-
"ALTER COLLATION %s REFRESH VERSION, "
1493-
"or build PostgreSQL with the right library version.",
1494-
quote_qualified_identifier(get_namespace_name(collform->collnamespace),
1495-
NameStr(collform->collname)))));
1496-
}
1497-
1498-
ReleaseSysCache(tp);
1467+
CollationCacheContext = AllocSetContextCreate(TopMemoryContext,
1468+
"collation cache",
1469+
ALLOCSET_DEFAULT_SIZES);
1470+
CollationCache = collation_cache_create(CollationCacheContext,
1471+
16, NULL);
1472+
}
14991473

1500-
/* We'll keep the pg_locale_t structures in TopMemoryContext */
1501-
resultp = MemoryContextAlloc(TopMemoryContext, sizeof(*resultp));
1502-
*resultp = result;
1474+
cache_entry = collation_cache_insert(CollationCache, collid, &found);
1475+
if (!found)
1476+
{
1477+
/*
1478+
* Make sure cache entry is marked invalid, in case we fail before
1479+
* setting things.
1480+
*/
1481+
cache_entry->locale = 0;
1482+
}
15031483

1504-
cache_entry->locale = resultp;
1484+
if (cache_entry->locale == 0)
1485+
{
1486+
cache_entry->locale = create_pg_locale(collid, CollationCacheContext);
15051487
}
15061488

15071489
last_collation_cache_oid = collid;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy