@@ -1215,42 +1215,135 @@ IsoLocaleName(const char *winlocname)
1215
1215
1216
1216
1217
1217
/*
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.
1224
1219
*/
1225
- static collation_cache_entry *
1226
- lookup_collation_cache (Oid collation )
1220
+ static pg_locale_t
1221
+ create_pg_locale (Oid collid , MemoryContext context )
1227
1222
{
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 ;
1230
1228
1231
- Assert (OidIsValid (collation ));
1232
- Assert (collation != DEFAULT_COLLATION_OID );
1229
+ result = MemoryContextAllocZero (context , sizeof (struct pg_locale_struct ));
1233
1230
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 )
1235
1240
{
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 );
1241
1253
}
1254
+ else if (collform -> collprovider == COLLPROVIDER_ICU )
1255
+ {
1256
+ #ifdef USE_ICU
1257
+ const char * iculocstr ;
1258
+ const char * icurules ;
1242
1259
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 )
1245
1282
{
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 )))));
1251
1342
}
1252
1343
1253
- return cache_entry ;
1344
+ ReleaseSysCache (tp );
1345
+
1346
+ return result ;
1254
1347
}
1255
1348
1256
1349
/*
@@ -1358,6 +1451,7 @@ pg_locale_t
1358
1451
pg_newlocale_from_collation (Oid collid )
1359
1452
{
1360
1453
collation_cache_entry * cache_entry ;
1454
+ bool found ;
1361
1455
1362
1456
if (collid == DEFAULT_COLLATION_OID )
1363
1457
return & default_locale ;
@@ -1368,140 +1462,28 @@ pg_newlocale_from_collation(Oid collid)
1368
1462
if (last_collation_cache_oid == collid )
1369
1463
return last_collation_cache_locale ;
1370
1464
1371
- cache_entry = lookup_collation_cache (collid );
1372
-
1373
- if (cache_entry -> locale == 0 )
1465
+ if (CollationCache == NULL )
1374
1466
{
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
+ }
1499
1473
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
+ }
1503
1483
1504
- cache_entry -> locale = resultp ;
1484
+ if (cache_entry -> locale == 0 )
1485
+ {
1486
+ cache_entry -> locale = create_pg_locale (collid , CollationCacheContext );
1505
1487
}
1506
1488
1507
1489
last_collation_cache_oid = collid ;
0 commit comments