@@ -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
13581451pg_newlocale_from_collation (Oid collid )
13591452{
13601453collation_cache_entry * cache_entry ;
1454+ bool found ;
13611455
13621456if (collid == DEFAULT_COLLATION_OID )
13631457return & default_locale ;
@@ -1368,140 +1462,28 @@ pg_newlocale_from_collation(Oid collid)
13681462if (last_collation_cache_oid == collid )
13691463return 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
15071489last_collation_cache_oid = collid ;