Line data Source code
1 : /*-----------------------------------------------------------------------
2 : *
3 : * PostgreSQL locale utilities for builtin provider
4 : *
5 : * Portions Copyright (c) 2002-2024, PostgreSQL Global Development Group
6 : *
7 : * src/backend/utils/adt/pg_locale_builtin.c
8 : *
9 : *-----------------------------------------------------------------------
10 : */
11 :
12 : #include "postgres.h"
13 :
14 : #include "catalog/pg_database.h"
15 : #include "catalog/pg_collation.h"
16 : #include "common/unicode_case.h"
17 : #include "common/unicode_category.h"
18 : #include "mb/pg_wchar.h"
19 : #include "miscadmin.h"
20 : #include "utils/builtins.h"
21 : #include "utils/memutils.h"
22 : #include "utils/pg_locale.h"
23 : #include "utils/syscache.h"
24 :
25 : extern pg_locale_t create_pg_locale_builtin(Oid collid,
26 : MemoryContext context);
27 : extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
28 : ssize_t srclen, pg_locale_t locale);
29 : extern size_t strtitle_builtin(char *dst, size_t dstsize, const char *src,
30 : ssize_t srclen, pg_locale_t locale);
31 : extern size_t strupper_builtin(char *dst, size_t dstsize, const char *src,
32 : ssize_t srclen, pg_locale_t locale);
33 :
34 :
35 : struct WordBoundaryState
36 : {
37 : const char *str;
38 : size_t len;
39 : size_t offset;
40 : bool init;
41 : bool prev_alnum;
42 : };
43 :
44 : /*
45 : * Simple word boundary iterator that draws boundaries each time the result of
46 : * pg_u_isalnum() changes.
47 : */
48 : static size_t
49 344 : initcap_wbnext(void *state)
50 : {
51 344 : struct WordBoundaryState *wbstate = (struct WordBoundaryState *) state;
52 :
53 752 : while (wbstate->offset < wbstate->len &&
54 666 : wbstate->str[wbstate->offset] != '\0')
55 : {
56 666 : pg_wchar u = utf8_to_unicode((unsigned char *) wbstate->str +
57 666 : wbstate->offset);
58 666 : bool curr_alnum = pg_u_isalnum(u, true);
59 :
60 666 : if (!wbstate->init || curr_alnum != wbstate->prev_alnum)
61 : {
62 258 : size_t prev_offset = wbstate->offset;
63 :
64 258 : wbstate->init = true;
65 258 : wbstate->offset += unicode_utf8len(u);
66 258 : wbstate->prev_alnum = curr_alnum;
67 258 : return prev_offset;
68 : }
69 :
70 408 : wbstate->offset += unicode_utf8len(u);
71 : }
72 :
73 86 : return wbstate->len;
74 : }
75 :
76 : size_t
77 11768 : strlower_builtin(char *dest, size_t destsize, const char *src, ssize_t srclen,
78 : pg_locale_t locale)
79 : {
80 11768 : return unicode_strlower(dest, destsize, src, srclen);
81 : }
82 :
83 : size_t
84 86 : strtitle_builtin(char *dest, size_t destsize, const char *src, ssize_t srclen,
85 : pg_locale_t locale)
86 : {
87 86 : struct WordBoundaryState wbstate = {
88 : .str = src,
89 : .len = srclen,
90 : .offset = 0,
91 : .init = false,
92 : .prev_alnum = false,
93 : };
94 :
95 86 : return unicode_strtitle(dest, destsize, src, srclen,
96 : initcap_wbnext, &wbstate);
97 : }
98 :
99 : size_t
100 316786 : strupper_builtin(char *dest, size_t destsize, const char *src, ssize_t srclen,
101 : pg_locale_t locale)
102 : {
103 316786 : return unicode_strupper(dest, destsize, src, srclen);
104 : }
105 :
106 : pg_locale_t
107 1728 : create_pg_locale_builtin(Oid collid, MemoryContext context)
108 : {
109 : const char *locstr;
110 : pg_locale_t result;
111 :
112 1728 : if (collid == DEFAULT_COLLATION_OID)
113 : {
114 : HeapTuple tp;
115 : Datum datum;
116 :
117 1690 : tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
118 1690 : if (!HeapTupleIsValid(tp))
119 0 : elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
120 1690 : datum = SysCacheGetAttrNotNull(DATABASEOID, tp,
121 : Anum_pg_database_datlocale);
122 1690 : locstr = TextDatumGetCString(datum);
123 1690 : ReleaseSysCache(tp);
124 : }
125 : else
126 : {
127 : HeapTuple tp;
128 : Datum datum;
129 :
130 38 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
131 38 : if (!HeapTupleIsValid(tp))
132 0 : elog(ERROR, "cache lookup failed for collation %u", collid);
133 38 : datum = SysCacheGetAttrNotNull(COLLOID, tp,
134 : Anum_pg_collation_colllocale);
135 38 : locstr = TextDatumGetCString(datum);
136 38 : ReleaseSysCache(tp);
137 : }
138 :
139 1728 : builtin_validate_locale(GetDatabaseEncoding(), locstr);
140 :
141 1728 : result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
142 :
143 1728 : result->info.builtin.locale = MemoryContextStrdup(context, locstr);
144 1728 : result->provider = COLLPROVIDER_BUILTIN;
145 1728 : result->deterministic = true;
146 1728 : result->collate_is_c = true;
147 1728 : result->ctype_is_c = (strcmp(locstr, "C") == 0);
148 :
149 1728 : return result;
150 : }
|