@@ -1461,6 +1461,103 @@ lc_ctype_is_c(Oid collation)
1461
1461
return (lookup_collation_cache (collation , true))-> ctype_is_c ;
1462
1462
}
1463
1463
1464
+ /* simple subroutine for reporting errors from newlocale() */
1465
+ static void
1466
+ report_newlocale_failure (const char * localename )
1467
+ {
1468
+ int save_errno ;
1469
+
1470
+ /*
1471
+ * Windows doesn't provide any useful error indication from
1472
+ * _create_locale(), and BSD-derived platforms don't seem to feel they
1473
+ * need to set errno either (even though POSIX is pretty clear that
1474
+ * newlocale should do so). So, if errno hasn't been set, assume ENOENT
1475
+ * is what to report.
1476
+ */
1477
+ if (errno == 0 )
1478
+ errno = ENOENT ;
1479
+
1480
+ /*
1481
+ * ENOENT means "no such locale", not "no such file", so clarify that
1482
+ * errno with an errdetail message.
1483
+ */
1484
+ save_errno = errno ; /* auxiliary funcs might change errno */
1485
+ ereport (ERROR ,
1486
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1487
+ errmsg ("could not create locale \"%s\": %m" ,
1488
+ localename ),
1489
+ (save_errno == ENOENT ?
1490
+ errdetail ("The operating system could not find any locale data for the locale name \"%s\"." ,
1491
+ localename ) : 0 )));
1492
+ }
1493
+
1494
+ /*
1495
+ * Initialize the locale_t field.
1496
+ *
1497
+ * The "C" and "POSIX" locales are not actually handled by libc, so set the
1498
+ * locale_t to zero in that case.
1499
+ */
1500
+ static void
1501
+ make_libc_collator (const char * collate , const char * ctype ,
1502
+ pg_locale_t result )
1503
+ {
1504
+ locale_t loc = 0 ;
1505
+
1506
+ if (strcmp (collate , ctype ) == 0 )
1507
+ {
1508
+ if (strcmp (ctype , "C" ) != 0 && strcmp (ctype , "POSIX" ) != 0 )
1509
+ {
1510
+ /* Normal case where they're the same */
1511
+ errno = 0 ;
1512
+ #ifndef WIN32
1513
+ loc = newlocale (LC_COLLATE_MASK | LC_CTYPE_MASK , collate ,
1514
+ NULL );
1515
+ #else
1516
+ loc = _create_locale (LC_ALL , collate );
1517
+ #endif
1518
+ if (!loc )
1519
+ report_newlocale_failure (collate );
1520
+ }
1521
+ }
1522
+ else
1523
+ {
1524
+ #ifndef WIN32
1525
+ /* We need two newlocale() steps */
1526
+ locale_t loc1 = 0 ;
1527
+
1528
+ if (strcmp (collate , "C" ) != 0 && strcmp (collate , "POSIX" ) != 0 )
1529
+ {
1530
+ errno = 0 ;
1531
+ loc1 = newlocale (LC_COLLATE_MASK , collate , NULL );
1532
+ if (!loc1 )
1533
+ report_newlocale_failure (collate );
1534
+ }
1535
+
1536
+ if (strcmp (ctype , "C" ) != 0 && strcmp (ctype , "POSIX" ) != 0 )
1537
+ {
1538
+ errno = 0 ;
1539
+ loc = newlocale (LC_CTYPE_MASK , ctype , loc1 );
1540
+ if (!loc )
1541
+ report_newlocale_failure (ctype );
1542
+ }
1543
+ else
1544
+ loc = loc1 ;
1545
+ #else
1546
+
1547
+ /*
1548
+ * XXX The _create_locale() API doesn't appear to support this. Could
1549
+ * perhaps be worked around by changing pg_locale_t to contain two
1550
+ * separate fields.
1551
+ */
1552
+ ereport (ERROR ,
1553
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1554
+ errmsg ("collations with different collate and ctype values are not supported on this platform" )));
1555
+ #endif
1556
+ }
1557
+
1558
+ result -> info .lt = loc ;
1559
+ }
1560
+
1464
1561
void
1465
1562
make_icu_collator (const char * iculocstr ,
1466
1563
const char * icurules ,
@@ -1514,36 +1611,6 @@ make_icu_collator(const char *iculocstr,
1514
1611
}
1515
1612
1516
1613
1517
- /* simple subroutine for reporting errors from newlocale() */
1518
- static void
1519
- report_newlocale_failure (const char * localename )
1520
- {
1521
- int save_errno ;
1522
-
1523
- /*
1524
- * Windows doesn't provide any useful error indication from
1525
- * _create_locale(), and BSD-derived platforms don't seem to feel they
1526
- * need to set errno either (even though POSIX is pretty clear that
1527
- * newlocale should do so). So, if errno hasn't been set, assume ENOENT
1528
- * is what to report.
1529
- */
1530
- if (errno == 0 )
1531
- errno = ENOENT ;
1532
-
1533
- /*
1534
- * ENOENT means "no such locale", not "no such file", so clarify that
1535
- * errno with an errdetail message.
1536
- */
1537
- save_errno = errno ; /* auxiliary funcs might change errno */
1538
- ereport (ERROR ,
1539
- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1540
- errmsg ("could not create locale \"%s\": %m" ,
1541
- localename ),
1542
- (save_errno == ENOENT ?
1543
- errdetail ("The operating system could not find any locale data for the locale name \"%s\"." ,
1544
- localename ) : 0 )));
1545
- }
1546
-
1547
1614
bool
1548
1615
pg_locale_deterministic (pg_locale_t locale )
1549
1616
{
@@ -1601,7 +1668,17 @@ init_database_collation(void)
1601
1668
}
1602
1669
else
1603
1670
{
1671
+ const char * datcollate ;
1672
+ const char * datctype ;
1673
+
1604
1674
Assert (dbform -> datlocprovider == COLLPROVIDER_LIBC );
1675
+
1676
+ datum = SysCacheGetAttrNotNull (DATABASEOID , tup , Anum_pg_database_datcollate );
1677
+ datcollate = TextDatumGetCString (datum );
1678
+ datum = SysCacheGetAttrNotNull (DATABASEOID , tup , Anum_pg_database_datctype );
1679
+ datctype = TextDatumGetCString (datum );
1680
+
1681
+ make_libc_collator (datcollate , datctype , & default_locale );
1605
1682
}
1606
1683
1607
1684
default_locale .provider = dbform -> datlocprovider ;
@@ -1620,8 +1697,6 @@ init_database_collation(void)
1620
1697
* Create a pg_locale_t from a collation OID. Results are cached for the
1621
1698
* lifetime of the backend. Thus, do not free the result with freelocale().
1622
1699
*
1623
- * As a special optimization, the default/database collation returns 0.
1624
- *
1625
1700
* For simplicity, we always generate COLLATE + CTYPE even though we
1626
1701
* might only need one of them. Since this is called only once per session,
1627
1702
* it shouldn't cost much.
@@ -1635,12 +1710,7 @@ pg_newlocale_from_collation(Oid collid)
1635
1710
Assert (OidIsValid (collid ));
1636
1711
1637
1712
if (collid == DEFAULT_COLLATION_OID )
1638
- {
1639
- if (default_locale .provider == COLLPROVIDER_LIBC )
1640
- return (pg_locale_t ) 0 ;
1641
- else
1642
- return & default_locale ;
1643
- }
1713
+ return & default_locale ;
1644
1714
1645
1715
cache_entry = lookup_collation_cache (collid , false);
1646
1716
@@ -1679,55 +1749,14 @@ pg_newlocale_from_collation(Oid collid)
1679
1749
else if (collform -> collprovider == COLLPROVIDER_LIBC )
1680
1750
{
1681
1751
const char * collcollate ;
1682
- const char * collctype pg_attribute_unused ();
1683
- locale_t loc ;
1752
+ const char * collctype ;
1684
1753
1685
1754
datum = SysCacheGetAttrNotNull (COLLOID , tp , Anum_pg_collation_collcollate );
1686
1755
collcollate = TextDatumGetCString (datum );
1687
1756
datum = SysCacheGetAttrNotNull (COLLOID , tp , Anum_pg_collation_collctype );
1688
1757
collctype = TextDatumGetCString (datum );
1689
1758
1690
- if (strcmp (collcollate , collctype ) == 0 )
1691
- {
1692
- /* Normal case where they're the same */
1693
- errno = 0 ;
1694
- #ifndef WIN32
1695
- loc = newlocale (LC_COLLATE_MASK | LC_CTYPE_MASK , collcollate ,
1696
- NULL );
1697
- #else
1698
- loc = _create_locale (LC_ALL , collcollate );
1699
- #endif
1700
- if (!loc )
1701
- report_newlocale_failure (collcollate );
1702
- }
1703
- else
1704
- {
1705
- #ifndef WIN32
1706
- /* We need two newlocale() steps */
1707
- locale_t loc1 ;
1708
-
1709
- errno = 0 ;
1710
- loc1 = newlocale (LC_COLLATE_MASK , collcollate , NULL );
1711
- if (!loc1 )
1712
- report_newlocale_failure (collcollate );
1713
- errno = 0 ;
1714
- loc = newlocale (LC_CTYPE_MASK , collctype , loc1 );
1715
- if (!loc )
1716
- report_newlocale_failure (collctype );
1717
- #else
1718
-
1719
- /*
1720
- * XXX The _create_locale() API doesn't appear to support
1721
- * this. Could perhaps be worked around by changing
1722
- * pg_locale_t to contain two separate fields.
1723
- */
1724
- ereport (ERROR ,
1725
- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1726
- errmsg ("collations with different collate and ctype values are not supported on this platform" )));
1727
- #endif
1728
- }
1729
-
1730
- result .info .lt = loc ;
1759
+ make_libc_collator (collcollate , collctype , & result );
1731
1760
}
1732
1761
else if (collform -> collprovider == COLLPROVIDER_ICU )
1733
1762
{
0 commit comments