PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_locale_builtin.c
Go to the documentation of this file.
1/*-----------------------------------------------------------------------
2 *
3 * PostgreSQL locale utilities for builtin provider
4 *
5 * Portions Copyright (c) 2002-2026, 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"
16#include "common/unicode_case.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/*
26 * The largest text value must fit in MaxAllocSize, but then may grow during
27 * case mapping. While the resulting string will not be representable as a new
28 * text value, we must at least be sure not to overflow a size_t while
29 * processing it.
30 */
32 "case mapping may overflow size_t");
33
35 MemoryContext context);
37
39{
40 const char *str;
41 size_t len;
42 size_t offset;
43 bool posix;
44 bool init;
46};
47
48/*
49 * In UTF-8, pg_wchar is guaranteed to be the code point value.
50 */
51static inline char32_t
53{
55 return (char32_t) wc;
56}
57
58static inline pg_wchar
60{
62 return (pg_wchar) c32;
63}
64
65/*
66 * Simple word boundary iterator that draws boundaries each time the result of
67 * pg_u_isalnum() changes.
68 */
69static size_t
71{
73
74 while (wbstate->offset < wbstate->len)
75 {
76 int ulen = pg_utf_mblen((const unsigned char *) wbstate->str +
77 wbstate->offset);
78 char32_t u;
79 bool curr_alnum;
80 size_t prev_offset = wbstate->offset;
81
82 /* invalid UTF8 */
83 if (wbstate->offset + ulen > wbstate->len)
84 {
85 wbstate->init = true;
86 wbstate->offset = wbstate->len;
87 return prev_offset;
88 }
89
90 u = utf8_to_unicode((const unsigned char *) wbstate->str +
91 wbstate->offset);
92 curr_alnum = pg_u_isalnum(u, wbstate->posix);
93
94 if (!wbstate->init || curr_alnum != wbstate->prev_alnum)
95 {
96 wbstate->init = true;
97 wbstate->offset += ulen;
98 wbstate->prev_alnum = curr_alnum;
99 return prev_offset;
100 }
101
102 wbstate->offset += ulen;
103 }
104
105 return wbstate->len;
106}
107
108static size_t
109strlower_builtin(char *dest, size_t destsize, const char *src, size_t srclen,
110 pg_locale_t locale)
111{
112 size_t consumed;
113 size_t result;
114
116 locale->builtin.casemap_full);
117 if (consumed < srclen)
119 srclen - consumed);
120
121 return result;
122}
123
124static size_t
125strtitle_builtin(char *dest, size_t destsize, const char *src, size_t srclen,
126 pg_locale_t locale)
127{
128 struct WordBoundaryState wbstate = {
129 .str = src,
130 .len = srclen,
131 .offset = 0,
132 .posix = !locale->builtin.casemap_full,
133 .init = false,
134 .prev_alnum = false,
135 };
136 size_t consumed;
137 size_t result;
138
140 locale->builtin.casemap_full,
142
143 if (consumed < srclen)
145 srclen - consumed);
146
147 return result;
148}
149
150static size_t
151strupper_builtin(char *dest, size_t destsize, const char *src, size_t srclen,
152 pg_locale_t locale)
153{
154 size_t consumed;
155 size_t result;
156
158 locale->builtin.casemap_full);
159 if (consumed < srclen)
161 srclen - consumed);
162
163 return result;
164}
165
166static size_t
167strfold_builtin(char *dest, size_t destsize, const char *src, size_t srclen,
168 pg_locale_t locale)
169{
170 size_t consumed;
171 size_t result;
172
174 locale->builtin.casemap_full);
175 if (consumed < srclen)
177 srclen - consumed);
178
179 return result;
180}
181
182static bool
184{
185 return pg_u_isdigit(to_char32(wc), !locale->builtin.casemap_full);
186}
187
188static bool
190{
191 return pg_u_isalpha(to_char32(wc));
192}
193
194static bool
196{
197 return pg_u_isalnum(to_char32(wc), !locale->builtin.casemap_full);
198}
199
200static bool
202{
203 return pg_u_isupper(to_char32(wc));
204}
205
206static bool
208{
209 return pg_u_islower(to_char32(wc));
210}
211
212static bool
214{
215 return pg_u_isgraph(to_char32(wc));
216}
217
218static bool
220{
221 return pg_u_isprint(to_char32(wc));
222}
223
224static bool
226{
227 return pg_u_ispunct(to_char32(wc), !locale->builtin.casemap_full);
228}
229
230static bool
232{
233 return pg_u_isspace(to_char32(wc));
234}
235
236static bool
238{
239 return pg_u_isxdigit(to_char32(wc), !locale->builtin.casemap_full);
240}
241
242static bool
244{
245 return pg_u_prop_cased(to_char32(wc));
246}
247
248static pg_wchar
253
254static pg_wchar
259
262 .strtitle = strtitle_builtin,
263 .strupper = strupper_builtin,
264 .strfold = strfold_builtin,
265 /* uses plain ASCII semantics for historical reasons */
266 .downcase_ident = NULL,
267 .wc_isdigit = wc_isdigit_builtin,
268 .wc_isalpha = wc_isalpha_builtin,
269 .wc_isalnum = wc_isalnum_builtin,
270 .wc_isupper = wc_isupper_builtin,
271 .wc_islower = wc_islower_builtin,
272 .wc_isgraph = wc_isgraph_builtin,
273 .wc_isprint = wc_isprint_builtin,
274 .wc_ispunct = wc_ispunct_builtin,
275 .wc_isspace = wc_isspace_builtin,
276 .wc_isxdigit = wc_isxdigit_builtin,
277 .wc_iscased = wc_iscased_builtin,
278 .wc_tolower = wc_tolower_builtin,
279 .wc_toupper = wc_toupper_builtin,
280};
281
284{
285 const char *locstr;
287
289 {
290 HeapTuple tp;
291 Datum datum;
292
294 if (!HeapTupleIsValid(tp))
295 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
299 ReleaseSysCache(tp);
300 }
301 else
302 {
303 HeapTuple tp;
304 Datum datum;
305
307 if (!HeapTupleIsValid(tp))
308 elog(ERROR, "cache lookup failed for collation %u", collid);
312 ReleaseSysCache(tp);
313 }
314
316
317 result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
318
319 result->builtin.locale = MemoryContextStrdup(context, locstr);
320 result->builtin.casemap_full = (strcmp(locstr, "PG_UNICODE_FAST") == 0);
321 result->deterministic = true;
322 result->collate_is_c = true;
323 result->ctype_is_c = (strcmp(locstr, "C") == 0);
324 if (!result->ctype_is_c)
326
327 return result;
328}
329
330char *
332{
333 /*
334 * The only two supported locales (C and C.UTF-8) are both based on memcmp
335 * and are not expected to change, but track the version anyway.
336 *
337 * Note that the character semantics may change for some locales, but the
338 * collation version only tracks changes to sort order.
339 */
340 if (strcmp(collcollate, "C") == 0)
341 return "1";
342 else if (strcmp(collcollate, "C.UTF-8") == 0)
343 return "1";
344 else if (strcmp(collcollate, "PG_UNICODE_FAST") == 0)
345 return "1";
346 else
349 errmsg("invalid locale name \"%s\" for builtin provider",
350 collcollate)));
351
352 return NULL; /* keep compiler quiet */
353}
#define TextDatumGetCString(d)
Definition builtins.h:99
#define Assert(condition)
Definition c.h:1002
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1067
uint32 result
Oid collid
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define MaxAllocSize
Definition fe_memutils.h:22
Oid MyDatabaseId
Definition globals.c:96
#define HeapTupleIsValid(tuple)
Definition htup.h:78
#define PG_UTF8
Definition mbprint.c:43
unsigned int pg_wchar
Definition mbprint.c:31
static char32_t utf8_to_unicode(const unsigned char *c)
Definition mbprint.c:53
int GetDatabaseEncoding(void)
Definition mbutils.c:1389
void report_invalid_encoding(int encoding, const char *mbstr, int len)
Definition mbutils.c:1825
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1897
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1269
static char * errmsg
const char * builtin_validate_locale(int encoding, const char *locale)
Definition pg_locale.c:1691
static pg_wchar wc_toupper_builtin(pg_wchar wc, pg_locale_t locale)
static bool wc_isgraph_builtin(pg_wchar wc, pg_locale_t locale)
static size_t strtitle_builtin(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
static pg_wchar wc_tolower_builtin(pg_wchar wc, pg_locale_t locale)
static bool wc_islower_builtin(pg_wchar wc, pg_locale_t locale)
pg_locale_t create_pg_locale_builtin(Oid collid, MemoryContext context)
static bool wc_isprint_builtin(pg_wchar wc, pg_locale_t locale)
static size_t initcap_wbnext(void *state)
static bool wc_ispunct_builtin(pg_wchar wc, pg_locale_t locale)
static bool wc_iscased_builtin(pg_wchar wc, pg_locale_t locale)
static bool wc_isdigit_builtin(pg_wchar wc, pg_locale_t locale)
static bool wc_isupper_builtin(pg_wchar wc, pg_locale_t locale)
static pg_wchar to_pg_wchar(char32_t c32)
static char32_t to_char32(pg_wchar wc)
static size_t strfold_builtin(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
char * get_collation_actual_version_builtin(const char *collcollate)
static bool wc_isspace_builtin(pg_wchar wc, pg_locale_t locale)
static size_t strlower_builtin(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
static bool wc_isalpha_builtin(pg_wchar wc, pg_locale_t locale)
static size_t strupper_builtin(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
static bool wc_isxdigit_builtin(pg_wchar wc, pg_locale_t locale)
static bool wc_isalnum_builtin(pg_wchar wc, pg_locale_t locale)
static const struct ctype_methods ctype_methods_builtin
#define pg_utf_mblen
Definition pg_wchar.h:486
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static int fb(int x)
size_t(* strlower)(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
Definition pg_locale.h:101
struct pg_locale_struct::@170::@172 builtin
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
size_t unicode_strupper(char *dst, size_t dstsize, const char *src, size_t srclen, size_t *pconsumed, bool full)
size_t unicode_strfold(char *dst, size_t dstsize, const char *src, size_t srclen, size_t *pconsumed, bool full)
char32_t unicode_lowercase_simple(char32_t code)
size_t unicode_strlower(char *dst, size_t dstsize, const char *src, size_t srclen, size_t *pconsumed, bool full)
size_t unicode_strtitle(char *dst, size_t dstsize, const char *src, size_t srclen, size_t *pconsumed, bool full, WordBoundaryNext wbnext, void *wbstate)
char32_t unicode_uppercase_simple(char32_t code)
bool pg_u_isalnum(char32_t code, bool posix)
bool pg_u_prop_cased(char32_t code)
bool pg_u_isprint(char32_t code)
bool pg_u_islower(char32_t code)
bool pg_u_isdigit(char32_t code, bool posix)
bool pg_u_isalpha(char32_t code)
bool pg_u_isxdigit(char32_t code, bool posix)
bool pg_u_ispunct(char32_t code, bool posix)
bool pg_u_isgraph(char32_t code)
bool pg_u_isspace(char32_t code)
bool pg_u_isupper(char32_t code)
#define UTF8_MAX_CASEMAP_EXPANSION