Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * mbutils.c
4 : : * This file contains functions for encoding conversion.
5 : : *
6 : : * The string-conversion functions in this file share some API quirks.
7 : : * Note the following:
8 : : *
9 : : * The functions return a palloc'd, null-terminated string if conversion
10 : : * is required. However, if no conversion is performed, the given source
11 : : * string pointer is returned as-is.
12 : : *
13 : : * Although the presence of a length argument means that callers can pass
14 : : * non-null-terminated strings, care is required because the same string
15 : : * will be passed back if no conversion occurs. Such callers *must* check
16 : : * whether result == src and handle that case differently.
17 : : *
18 : : * If the source and destination encodings are the same, the source string
19 : : * is returned without any verification; it's assumed to be valid data.
20 : : * If that might not be the case, the caller is responsible for validating
21 : : * the string using a separate call to pg_verify_mbstr(). Whenever the
22 : : * source and destination encodings are different, the functions ensure that
23 : : * the result is validly encoded according to the destination encoding.
24 : : *
25 : : *
26 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
27 : : * Portions Copyright (c) 1994, Regents of the University of California
28 : : *
29 : : *
30 : : * IDENTIFICATION
31 : : * src/backend/utils/mb/mbutils.c
32 : : *
33 : : *-------------------------------------------------------------------------
34 : : */
35 : : #include "postgres.h"
36 : :
37 : : #include "access/xact.h"
38 : : #include "catalog/namespace.h"
39 : : #include "mb/pg_wchar.h"
40 : : #include "utils/fmgrprotos.h"
41 : : #include "utils/memdebug.h"
42 : : #include "utils/memutils.h"
43 : : #include "utils/relcache.h"
44 : : #include "varatt.h"
45 : :
46 : : /*
47 : : * We maintain a simple linked list caching the fmgr lookup info for the
48 : : * currently selected conversion functions, as well as any that have been
49 : : * selected previously in the current session. (We remember previous
50 : : * settings because we must be able to restore a previous setting during
51 : : * transaction rollback, without doing any fresh catalog accesses.)
52 : : *
53 : : * Since we'll never release this data, we just keep it in TopMemoryContext.
54 : : */
55 : : typedef struct ConvProcInfo
56 : : {
57 : : int s_encoding; /* server and client encoding IDs */
58 : : int c_encoding;
59 : : FmgrInfo to_server_info; /* lookup info for conversion procs */
60 : : FmgrInfo to_client_info;
61 : : } ConvProcInfo;
62 : :
63 : : static List *ConvProcList = NIL; /* List of ConvProcInfo */
64 : :
65 : : /*
66 : : * These variables point to the currently active conversion functions,
67 : : * or are NULL when no conversion is needed.
68 : : */
69 : : static FmgrInfo *ToServerConvProc = NULL;
70 : : static FmgrInfo *ToClientConvProc = NULL;
71 : :
72 : : /*
73 : : * This variable stores the conversion function to convert from UTF-8
74 : : * to the server encoding. It's NULL if the server encoding *is* UTF-8,
75 : : * or if we lack a conversion function for this.
76 : : */
77 : : static FmgrInfo *Utf8ToServerConvProc = NULL;
78 : :
79 : : /*
80 : : * These variables track the currently-selected encodings.
81 : : */
82 : : static const pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
83 : : static const pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
84 : : static const pg_enc2name *MessageEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
85 : :
86 : : /*
87 : : * During backend startup we can't set client encoding because we (a)
88 : : * can't look up the conversion functions, and (b) may not know the database
89 : : * encoding yet either. So SetClientEncoding() just accepts anything and
90 : : * remembers it for InitializeClientEncoding() to apply later.
91 : : */
92 : : static bool backend_startup_complete = false;
93 : : static int pending_client_encoding = PG_SQL_ASCII;
94 : :
95 : :
96 : : /* Internal functions */
97 : : static char *perform_default_encoding_conversion(const char *src,
98 : : int len, bool is_client_to_server);
99 : : static int cliplen(const char *str, int len, int limit);
100 : :
101 : : pg_noreturn
102 : : static void report_invalid_encoding_int(int encoding, const char *mbstr,
103 : : int mblen, int len);
104 : :
105 : : pg_noreturn
106 : : static void report_invalid_encoding_db(const char *mbstr, int mblen, int len);
107 : :
108 : :
109 : : /*
110 : : * Prepare for a future call to SetClientEncoding. Success should mean
111 : : * that SetClientEncoding is guaranteed to succeed for this encoding request.
112 : : *
113 : : * (But note that success before backend_startup_complete does not guarantee
114 : : * success after ...)
115 : : *
116 : : * Returns 0 if okay, -1 if not (bad encoding or can't support conversion)
117 : : */
118 : : int
5532 tgl@sss.pgh.pa.us 119 :CBC 35964 : PrepareClientEncoding(int encoding)
120 : : {
121 : : int current_server_encoding;
122 : : ListCell *lc;
123 : :
9032 ishii@postgresql.org 124 [ + - - + ]: 35964 : if (!PG_VALID_FE_ENCODING(encoding))
[ + - + -
- + ]
7444 neilc@samurai.com 125 :UBC 0 : return -1;
126 : :
127 : : /* Can't do anything during startup, per notes above */
8434 tgl@sss.pgh.pa.us 128 [ + + ]:CBC 35964 : if (!backend_startup_complete)
8717 ishii@postgresql.org 129 : 18031 : return 0;
130 : :
8434 tgl@sss.pgh.pa.us 131 : 17933 : current_server_encoding = GetDatabaseEncoding();
132 : :
133 : : /*
134 : : * Check for cases that require no conversion function.
135 : : */
136 [ + + + + ]: 17933 : if (current_server_encoding == encoding ||
7444 neilc@samurai.com 137 [ + + ]: 2024 : current_server_encoding == PG_SQL_ASCII ||
138 : : encoding == PG_SQL_ASCII)
8434 tgl@sss.pgh.pa.us 139 : 17917 : return 0;
140 : :
6267 141 [ + - ]: 16 : if (IsTransactionState())
142 : : {
143 : : /*
144 : : * If we're in a live transaction, it's safe to access the catalogs,
145 : : * so look up the functions. We repeat the lookup even if the info is
146 : : * already cached, so that we can react to changes in the contents of
147 : : * pg_conversion.
148 : : */
149 : : Oid to_server_proc,
150 : : to_client_proc;
151 : : ConvProcInfo *convinfo;
152 : : MemoryContext oldcontext;
153 : :
154 : 16 : to_server_proc = FindDefaultConversionProc(encoding,
155 : : current_server_encoding);
156 [ - + ]: 16 : if (!OidIsValid(to_server_proc))
6267 tgl@sss.pgh.pa.us 157 :UBC 0 : return -1;
6267 tgl@sss.pgh.pa.us 158 :CBC 16 : to_client_proc = FindDefaultConversionProc(current_server_encoding,
159 : : encoding);
160 [ - + ]: 16 : if (!OidIsValid(to_client_proc))
6267 tgl@sss.pgh.pa.us 161 :UBC 0 : return -1;
162 : :
163 : : /*
164 : : * Load the fmgr info into TopMemoryContext (could still fail here)
165 : : */
6267 tgl@sss.pgh.pa.us 166 :CBC 16 : convinfo = (ConvProcInfo *) MemoryContextAlloc(TopMemoryContext,
167 : : sizeof(ConvProcInfo));
168 : 16 : convinfo->s_encoding = current_server_encoding;
169 : 16 : convinfo->c_encoding = encoding;
170 : 16 : fmgr_info_cxt(to_server_proc, &convinfo->to_server_info,
171 : : TopMemoryContext);
172 : 16 : fmgr_info_cxt(to_client_proc, &convinfo->to_client_info,
173 : : TopMemoryContext);
174 : :
175 : : /* Attach new info to head of list */
176 : 16 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
177 : 16 : ConvProcList = lcons(convinfo, ConvProcList);
178 : 16 : MemoryContextSwitchTo(oldcontext);
179 : :
180 : : /*
181 : : * We cannot yet remove any older entry for the same encoding pair,
182 : : * since it could still be in use. SetClientEncoding will clean up.
183 : : */
184 : :
185 : 16 : return 0; /* success */
186 : : }
187 : : else
188 : : {
189 : : /*
190 : : * If we're not in a live transaction, the only thing we can do is
191 : : * restore a previous setting using the cache. This covers all
192 : : * transaction-rollback cases. The only case it might not work for is
193 : : * trying to change client_encoding on the fly by editing
194 : : * postgresql.conf and SIGHUP'ing. Which would probably be a stupid
195 : : * thing to do anyway.
196 : : */
6267 tgl@sss.pgh.pa.us 197 [ # # # # :UBC 0 : foreach(lc, ConvProcList)
# # ]
198 : : {
199 : 0 : ConvProcInfo *oldinfo = (ConvProcInfo *) lfirst(lc);
200 : :
201 [ # # ]: 0 : if (oldinfo->s_encoding == current_server_encoding &&
202 [ # # ]: 0 : oldinfo->c_encoding == encoding)
203 : 0 : return 0;
204 : : }
205 : :
206 : 0 : return -1; /* it's not cached, so fail */
207 : : }
208 : : }
209 : :
210 : : /*
211 : : * Set the active client encoding and set up the conversion-function pointers.
212 : : * PrepareClientEncoding should have been called previously for this encoding.
213 : : *
214 : : * Returns 0 if okay, -1 if not (bad encoding or can't support conversion)
215 : : */
216 : : int
5532 tgl@sss.pgh.pa.us 217 :CBC 37882 : SetClientEncoding(int encoding)
218 : : {
219 : : int current_server_encoding;
220 : : bool found;
221 : : ListCell *lc;
222 : :
223 [ + - - + ]: 37882 : if (!PG_VALID_FE_ENCODING(encoding))
[ + - + -
- + ]
5532 tgl@sss.pgh.pa.us 224 :UBC 0 : return -1;
225 : :
226 : : /* Can't do anything during startup, per notes above */
5532 tgl@sss.pgh.pa.us 227 [ + + ]:CBC 37882 : if (!backend_startup_complete)
228 : : {
229 : 17950 : pending_client_encoding = encoding;
230 : 17950 : return 0;
231 : : }
232 : :
233 : 19932 : current_server_encoding = GetDatabaseEncoding();
234 : :
235 : : /*
236 : : * Check for cases that require no conversion function.
237 : : */
238 [ + + + + ]: 19932 : if (current_server_encoding == encoding ||
239 [ + + ]: 2024 : current_server_encoding == PG_SQL_ASCII ||
240 : : encoding == PG_SQL_ASCII)
241 : : {
242 : 19916 : ClientEncoding = &pg_enc2name_tbl[encoding];
243 : 19916 : ToServerConvProc = NULL;
244 : 19916 : ToClientConvProc = NULL;
245 : 19916 : return 0;
246 : : }
247 : :
248 : : /*
249 : : * Search the cache for the entry previously prepared by
250 : : * PrepareClientEncoding; if there isn't one, we lose. While at it,
251 : : * release any duplicate entries so that repeated Prepare/Set cycles don't
252 : : * leak memory.
253 : : */
254 : 16 : found = false;
2511 255 [ + - + + : 44 : foreach(lc, ConvProcList)
+ + ]
256 : : {
5532 257 : 28 : ConvProcInfo *convinfo = (ConvProcInfo *) lfirst(lc);
258 : :
259 [ + - ]: 28 : if (convinfo->s_encoding == current_server_encoding &&
260 [ + + ]: 28 : convinfo->c_encoding == encoding)
261 : : {
262 [ + + ]: 20 : if (!found)
263 : : {
264 : : /* Found newest entry, so set up */
265 : 16 : ClientEncoding = &pg_enc2name_tbl[encoding];
266 : 16 : ToServerConvProc = &convinfo->to_server_info;
267 : 16 : ToClientConvProc = &convinfo->to_client_info;
268 : 16 : found = true;
269 : : }
270 : : else
271 : : {
272 : : /* Duplicate entry, release it */
2511 tgl@sss.pgh.pa.us 273 :GBC 4 : ConvProcList = foreach_delete_current(ConvProcList, lc);
5532 274 : 4 : pfree(convinfo);
275 : : }
276 : : }
277 : : }
278 : :
5532 tgl@sss.pgh.pa.us 279 [ + - ]:CBC 16 : if (found)
280 : 16 : return 0; /* success */
281 : : else
5532 tgl@sss.pgh.pa.us 282 :UBC 0 : return -1; /* it's not cached, so fail */
283 : : }
284 : :
285 : : /*
286 : : * Initialize client encoding conversions.
287 : : * Called from InitPostgres() once during backend startup.
288 : : */
289 : : void
8434 tgl@sss.pgh.pa.us 290 :CBC 17552 : InitializeClientEncoding(void)
291 : : {
292 : : int current_server_encoding;
293 : :
294 [ - + ]: 17552 : Assert(!backend_startup_complete);
295 : 17552 : backend_startup_complete = true;
296 : :
5532 297 [ + - - + ]: 35104 : if (PrepareClientEncoding(pending_client_encoding) < 0 ||
298 : 17552 : SetClientEncoding(pending_client_encoding) < 0)
299 : : {
300 : : /*
301 : : * Oops, the requested conversion is not available. We couldn't fail
302 : : * before, but we can now.
303 : : */
8345 tgl@sss.pgh.pa.us 304 [ # # ]:UBC 0 : ereport(FATAL,
305 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
306 : : errmsg("conversion between %s and %s is not supported",
307 : : pg_enc2name_tbl[pending_client_encoding].name,
308 : : GetDatabaseEncodingName())));
309 : : }
310 : :
311 : : /*
312 : : * Also look up the UTF8-to-server conversion function if needed. Since
313 : : * the server encoding is fixed within any one backend process, we don't
314 : : * have to do this more than once.
315 : : */
2276 tgl@sss.pgh.pa.us 316 :CBC 17552 : current_server_encoding = GetDatabaseEncoding();
317 [ + + + + ]: 17552 : if (current_server_encoding != PG_UTF8 &&
318 : : current_server_encoding != PG_SQL_ASCII)
319 : : {
320 : : Oid utf8_to_server_proc;
321 : :
408 noah@leadboat.com 322 : 93 : AssertCouldGetRelation();
323 : : utf8_to_server_proc =
2276 tgl@sss.pgh.pa.us 324 : 93 : FindDefaultConversionProc(PG_UTF8,
325 : : current_server_encoding);
326 : : /* If there's no such conversion, just leave the pointer as NULL */
327 [ + - ]: 93 : if (OidIsValid(utf8_to_server_proc))
328 : : {
329 : : FmgrInfo *finfo;
330 : :
331 : 93 : finfo = (FmgrInfo *) MemoryContextAlloc(TopMemoryContext,
332 : : sizeof(FmgrInfo));
333 : 93 : fmgr_info_cxt(utf8_to_server_proc, finfo,
334 : : TopMemoryContext);
335 : : /* Set Utf8ToServerConvProc only after data is fully valid */
336 : 93 : Utf8ToServerConvProc = finfo;
337 : : }
338 : : }
8501 ishii@postgresql.org 339 : 17552 : }
340 : :
341 : : /*
342 : : * returns the current client encoding
343 : : */
344 : : int
9017 tgl@sss.pgh.pa.us 345 : 6386 : pg_get_client_encoding(void)
346 : : {
7444 neilc@samurai.com 347 : 6386 : return ClientEncoding->encoding;
348 : : }
349 : :
350 : : /*
351 : : * returns the current client encoding name
352 : : */
353 : : const char *
9017 tgl@sss.pgh.pa.us 354 :UBC 0 : pg_get_client_encoding_name(void)
355 : : {
7444 neilc@samurai.com 356 : 0 : return ClientEncoding->name;
357 : : }
358 : :
359 : : /*
360 : : * Convert src string to another encoding (general case).
361 : : *
362 : : * See the notes about string conversion functions at the top of this file.
363 : : */
364 : : unsigned char *
9017 tgl@sss.pgh.pa.us 365 :CBC 1926 : pg_do_encoding_conversion(unsigned char *src, int len,
366 : : int src_encoding, int dest_encoding)
367 : : {
368 : : unsigned char *result;
369 : : Oid proc;
370 : :
4479 371 [ + + ]: 1926 : if (len <= 0)
372 : 24 : return src; /* empty string is always valid */
373 : :
8717 ishii@postgresql.org 374 [ + + ]: 1902 : if (src_encoding == dest_encoding)
4479 tgl@sss.pgh.pa.us 375 : 1474 : return src; /* no conversion required, assume valid */
376 : :
377 [ - + ]: 428 : if (dest_encoding == PG_SQL_ASCII)
4479 tgl@sss.pgh.pa.us 378 :UBC 0 : return src; /* any string is valid in SQL_ASCII */
379 : :
4479 tgl@sss.pgh.pa.us 380 [ + + ]:CBC 428 : if (src_encoding == PG_SQL_ASCII)
381 : : {
382 : : /* No conversion is possible, but we must validate the result */
383 : 8 : (void) pg_verify_mbstr(dest_encoding, (const char *) src, len, false);
8586 ishii@postgresql.org 384 : 8 : return src;
385 : : }
386 : :
4479 tgl@sss.pgh.pa.us 387 [ - + ]: 420 : if (!IsTransactionState()) /* shouldn't happen */
4479 tgl@sss.pgh.pa.us 388 [ # # ]:UBC 0 : elog(ERROR, "cannot perform encoding conversion outside a transaction");
389 : :
8717 ishii@postgresql.org 390 :CBC 420 : proc = FindDefaultConversionProc(src_encoding, dest_encoding);
391 [ - + ]: 420 : if (!OidIsValid(proc))
4479 tgl@sss.pgh.pa.us 392 [ # # ]:UBC 0 : ereport(ERROR,
393 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
394 : : errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
395 : : pg_encoding_to_char(src_encoding),
396 : : pg_encoding_to_char(dest_encoding))));
397 : :
398 : : /*
399 : : * Allocate space for conversion result, being wary of integer overflow.
400 : : *
401 : : * len * MAX_CONVERSION_GROWTH is typically a vast overestimate of the
402 : : * required space, so it might exceed MaxAllocSize even though the result
403 : : * would actually fit. We do not want to hand back a result string that
404 : : * exceeds MaxAllocSize, because callers might not cope gracefully --- but
405 : : * if we just allocate more than that, and don't use it, that's fine.
406 : : */
2431 tgl@sss.pgh.pa.us 407 [ - + ]:CBC 420 : if ((Size) len >= (MaxAllocHugeSize / (Size) MAX_CONVERSION_GROWTH))
6942 tgl@sss.pgh.pa.us 408 [ # # ]:UBC 0 : ereport(ERROR,
409 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
410 : : errmsg("out of memory"),
411 : : errdetail("String of %d bytes is too long for encoding conversion.",
412 : : len)));
413 : :
414 : : result = (unsigned char *)
2431 tgl@sss.pgh.pa.us 415 :CBC 420 : MemoryContextAllocHuge(CurrentMemoryContext,
416 : 420 : (Size) len * MAX_CONVERSION_GROWTH + 1);
417 : :
1885 heikki.linnakangas@i 418 : 420 : (void) OidFunctionCall6(proc,
419 : : Int32GetDatum(src_encoding),
420 : : Int32GetDatum(dest_encoding),
421 : : CStringGetDatum((char *) src),
422 : : CStringGetDatum((char *) result),
423 : : Int32GetDatum(len),
424 : : BoolGetDatum(false));
425 : :
426 : : /*
427 : : * If the result is large, it's worth repalloc'ing to release any extra
428 : : * space we asked for. The cutoff here is somewhat arbitrary, but we
429 : : * *must* check when len * MAX_CONVERSION_GROWTH exceeds MaxAllocSize.
430 : : */
2431 tgl@sss.pgh.pa.us 431 [ - + ]: 420 : if (len > 1000000)
432 : : {
2431 tgl@sss.pgh.pa.us 433 :UBC 0 : Size resultlen = strlen((char *) result);
434 : :
435 [ # # ]: 0 : if (resultlen >= MaxAllocSize)
436 [ # # ]: 0 : ereport(ERROR,
437 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
438 : : errmsg("out of memory"),
439 : : errdetail("String of %d bytes is too long for encoding conversion.",
440 : : len)));
441 : :
442 : 0 : result = (unsigned char *) repalloc(result, resultlen + 1);
443 : : }
444 : :
9758 tgl@sss.pgh.pa.us 445 :CBC 420 : return result;
446 : : }
447 : :
448 : : /*
449 : : * Convert src string to another encoding.
450 : : *
451 : : * This function has a different API than the other conversion functions.
452 : : * The caller should've looked up the conversion function using
453 : : * FindDefaultConversionProc(). Unlike the other functions, the converted
454 : : * result is not palloc'd. It is written to the caller-supplied buffer
455 : : * instead.
456 : : *
457 : : * src_encoding - encoding to convert from
458 : : * dest_encoding - encoding to convert to
459 : : * src, srclen - input buffer and its length in bytes
460 : : * dest, destlen - destination buffer and its size in bytes
461 : : *
462 : : * The output is null-terminated.
463 : : *
464 : : * If destlen < srclen * MAX_CONVERSION_INPUT_LENGTH + 1, the converted output
465 : : * wouldn't necessarily fit in the output buffer, and the function will not
466 : : * convert the whole input.
467 : : *
468 : : * TODO: The conversion function interface is not great. Firstly, it
469 : : * would be nice to pass through the destination buffer size to the
470 : : * conversion function, so that if you pass a shorter destination buffer, it
471 : : * could still continue to fill up the whole buffer. Currently, we have to
472 : : * assume worst case expansion and stop the conversion short, even if there
473 : : * is in fact space left in the destination buffer. Secondly, it would be
474 : : * nice to return the number of bytes written to the caller, to avoid a call
475 : : * to strlen().
476 : : */
477 : : int
1885 heikki.linnakangas@i 478 : 2620 : pg_do_encoding_conversion_buf(Oid proc,
479 : : int src_encoding,
480 : : int dest_encoding,
481 : : unsigned char *src, int srclen,
482 : : unsigned char *dest, int destlen,
483 : : bool noError)
484 : : {
485 : : Datum result;
486 : :
487 : : /*
488 : : * If the destination buffer is not large enough to hold the result in the
489 : : * worst case, limit the input size passed to the conversion function.
490 : : */
491 [ + + ]: 2620 : if ((Size) srclen >= ((destlen - 1) / (Size) MAX_CONVERSION_GROWTH))
492 : 2580 : srclen = ((destlen - 1) / (Size) MAX_CONVERSION_GROWTH);
493 : :
494 : 2620 : result = OidFunctionCall6(proc,
495 : : Int32GetDatum(src_encoding),
496 : : Int32GetDatum(dest_encoding),
497 : : CStringGetDatum((char *) src),
498 : : CStringGetDatum((char *) dest),
499 : : Int32GetDatum(srclen),
500 : : BoolGetDatum(noError));
501 : 1580 : return DatumGetInt32(result);
502 : : }
503 : :
504 : : /*
505 : : * Convert string to encoding encoding_name. The source
506 : : * encoding is the DB encoding.
507 : : *
508 : : * BYTEA convert_to(TEXT string, NAME encoding_name)
509 : : */
510 : : Datum
6829 andrew@dunslane.net 511 : 272 : pg_convert_to(PG_FUNCTION_ARGS)
512 : : {
8669 bruce@momjian.us 513 : 272 : Datum string = PG_GETARG_DATUM(0);
514 : 272 : Datum dest_encoding_name = PG_GETARG_DATUM(1);
6716 tgl@sss.pgh.pa.us 515 : 272 : Datum src_encoding_name = DirectFunctionCall1(namein,
516 : : CStringGetDatum(DatabaseEncoding->name));
517 : : Datum result;
518 : :
519 : : /*
520 : : * pg_convert expects a bytea as its first argument. We're passing it a
521 : : * text argument here, relying on the fact that they are both in fact
522 : : * varlena types, and thus structurally identical.
523 : : */
524 : 272 : result = DirectFunctionCall3(pg_convert, string,
525 : : src_encoding_name, dest_encoding_name);
526 : :
6622 527 : 268 : PG_RETURN_DATUM(result);
528 : : }
529 : :
530 : : /*
531 : : * Convert string from encoding encoding_name. The destination
532 : : * encoding is the DB encoding.
533 : : *
534 : : * TEXT convert_from(BYTEA string, NAME encoding_name)
535 : : */
536 : : Datum
6829 andrew@dunslane.net 537 : 396 : pg_convert_from(PG_FUNCTION_ARGS)
538 : : {
539 : 396 : Datum string = PG_GETARG_DATUM(0);
540 : 396 : Datum src_encoding_name = PG_GETARG_DATUM(1);
6716 tgl@sss.pgh.pa.us 541 : 396 : Datum dest_encoding_name = DirectFunctionCall1(namein,
542 : : CStringGetDatum(DatabaseEncoding->name));
543 : : Datum result;
544 : :
545 : 396 : result = DirectFunctionCall3(pg_convert, string,
546 : : src_encoding_name, dest_encoding_name);
547 : :
548 : : /*
549 : : * pg_convert returns a bytea, which we in turn return as text, relying on
550 : : * the fact that they are both in fact varlena types, and thus
551 : : * structurally identical. Although not all bytea values are valid text,
552 : : * in this case it will be because we've told pg_convert to return one
553 : : * that is valid as text in the current database encoding.
554 : : */
6622 555 : 392 : PG_RETURN_DATUM(result);
556 : : }
557 : :
558 : : /*
559 : : * Convert string between two arbitrary encodings.
560 : : *
561 : : * BYTEA convert(BYTEA string, NAME src_encoding_name, NAME dest_encoding_name)
562 : : */
563 : : Datum
6829 andrew@dunslane.net 564 : 1060 : pg_convert(PG_FUNCTION_ARGS)
565 : : {
5657 itagaki.takahiro@gma 566 : 1060 : bytea *string = PG_GETARG_BYTEA_PP(0);
8983 bruce@momjian.us 567 : 1060 : char *src_encoding_name = NameStr(*PG_GETARG_NAME(1));
568 : 1060 : int src_encoding = pg_char_to_encoding(src_encoding_name);
569 : 1060 : char *dest_encoding_name = NameStr(*PG_GETARG_NAME(2));
570 : 1060 : int dest_encoding = pg_char_to_encoding(dest_encoding_name);
571 : : const char *src_str;
572 : : char *dest_str;
573 : : bytea *retval;
574 : : int len;
575 : :
9054 ishii@postgresql.org 576 [ - + ]: 1060 : if (src_encoding < 0)
8345 tgl@sss.pgh.pa.us 577 [ # # ]:UBC 0 : ereport(ERROR,
578 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
579 : : errmsg("invalid source encoding name \"%s\"",
580 : : src_encoding_name)));
9054 ishii@postgresql.org 581 [ - + ]:CBC 1060 : if (dest_encoding < 0)
8345 tgl@sss.pgh.pa.us 582 [ # # ]:UBC 0 : ereport(ERROR,
583 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
584 : : errmsg("invalid destination encoding name \"%s\"",
585 : : dest_encoding_name)));
586 : :
587 : : /* make sure that source string is valid */
5657 itagaki.takahiro@gma 588 [ - + - - :CBC 1060 : len = VARSIZE_ANY_EXHDR(string);
- - - - +
+ ]
589 [ + + ]: 1060 : src_str = VARDATA_ANY(string);
1948 heikki.linnakangas@i 590 : 1060 : (void) pg_verify_mbstr(src_encoding, src_str, len, false);
591 : :
592 : : /* perform conversion */
2678 peter@eisentraut.org 593 : 1052 : dest_str = (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, src_str),
594 : : len,
595 : : src_encoding,
596 : : dest_encoding);
597 : :
598 : :
599 : : /* return source string if no conversion happened */
908 nathan@postgresql.or 600 [ + + ]: 1052 : if (dest_str == src_str)
601 : 652 : PG_RETURN_BYTEA_P(string);
602 : :
603 : : /*
604 : : * build bytea data type structure.
605 : : */
606 : 400 : len = strlen(dest_str);
5657 itagaki.takahiro@gma 607 : 400 : retval = (bytea *) palloc(len + VARHDRSZ);
608 : 400 : SET_VARSIZE(retval, len + VARHDRSZ);
609 : 400 : memcpy(VARDATA(retval), dest_str, len);
908 nathan@postgresql.or 610 : 400 : pfree(dest_str);
611 : :
612 : : /* free memory if allocated by the toaster */
9054 ishii@postgresql.org 613 [ - + ]: 400 : PG_FREE_IF_COPY(string, 0);
614 : :
6829 andrew@dunslane.net 615 : 400 : PG_RETURN_BYTEA_P(retval);
616 : : }
617 : :
618 : : /*
619 : : * get the length of the string considered as text in the specified
620 : : * encoding. Raises an error if the data is not valid in that
621 : : * encoding.
622 : : *
623 : : * INT4 length (BYTEA string, NAME src_encoding_name)
624 : : */
625 : : Datum
6829 andrew@dunslane.net 626 :UBC 0 : length_in_encoding(PG_FUNCTION_ARGS)
627 : : {
4479 tgl@sss.pgh.pa.us 628 : 0 : bytea *string = PG_GETARG_BYTEA_PP(0);
6829 andrew@dunslane.net 629 : 0 : char *src_encoding_name = NameStr(*PG_GETARG_NAME(1));
630 : 0 : int src_encoding = pg_char_to_encoding(src_encoding_name);
631 : : const char *src_str;
632 : : int len;
633 : : int retval;
634 : :
6804 tgl@sss.pgh.pa.us 635 [ # # ]: 0 : if (src_encoding < 0)
636 [ # # ]: 0 : ereport(ERROR,
637 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
638 : : errmsg("invalid encoding name \"%s\"",
639 : : src_encoding_name)));
640 : :
4479 641 [ # # # # : 0 : len = VARSIZE_ANY_EXHDR(string);
# # # # #
# ]
642 [ # # ]: 0 : src_str = VARDATA_ANY(string);
643 : :
644 : 0 : retval = pg_verify_mbstr_len(src_encoding, src_str, len, false);
645 : :
646 : 0 : PG_RETURN_INT32(retval);
647 : : }
648 : :
649 : : /*
650 : : * Get maximum multibyte character length in the specified encoding.
651 : : *
652 : : * Note encoding is specified numerically, not by name as above.
653 : : */
654 : : Datum
6171 peter_e@gmx.net 655 : 0 : pg_encoding_max_length_sql(PG_FUNCTION_ARGS)
656 : : {
5937 bruce@momjian.us 657 : 0 : int encoding = PG_GETARG_INT32(0);
658 : :
6171 peter_e@gmx.net 659 [ # # # # ]: 0 : if (PG_VALID_ENCODING(encoding))
[ # # # #
# # ]
tgl@sss.pgh.pa.us 660 : 0 : PG_RETURN_INT32(pg_wchar_table[encoding].maxmblen);
661 : : else
peter_e@gmx.net 662 : 0 : PG_RETURN_NULL();
663 : : }
664 : :
665 : : /*
666 : : * Convert client encoding to server encoding.
667 : : *
668 : : * See the notes about string conversion functions at the top of this file.
669 : : */
670 : : char *
7553 tgl@sss.pgh.pa.us 671 :CBC 499855 : pg_client_to_server(const char *s, int len)
672 : : {
5577 itagaki.takahiro@gma 673 : 499855 : return pg_any_to_server(s, len, ClientEncoding->encoding);
674 : : }
675 : :
676 : : /*
677 : : * Convert any encoding to server encoding.
678 : : *
679 : : * See the notes about string conversion functions at the top of this file.
680 : : *
681 : : * Unlike the other string conversion functions, this will apply validation
682 : : * even if encoding == DatabaseEncoding->encoding. This is because this is
683 : : * used to process data coming in from outside the database, and we never
684 : : * want to just assume validity.
685 : : */
686 : : char *
687 : 548285 : pg_any_to_server(const char *s, int len, int encoding)
688 : : {
7314 tgl@sss.pgh.pa.us 689 [ + + ]: 548285 : if (len <= 0)
2565 690 : 36895 : return unconstify(char *, s); /* empty string is always valid */
691 : :
5577 itagaki.takahiro@gma 692 [ + + + + ]: 511390 : if (encoding == DatabaseEncoding->encoding ||
693 : : encoding == PG_SQL_ASCII)
694 : : {
695 : : /*
696 : : * No conversion is needed, but we must still validate the data.
697 : : */
7314 tgl@sss.pgh.pa.us 698 : 511185 : (void) pg_verify_mbstr(DatabaseEncoding->encoding, s, len, false);
2678 peter@eisentraut.org 699 : 511184 : return unconstify(char *, s);
700 : : }
701 : :
7314 tgl@sss.pgh.pa.us 702 [ + + ]: 205 : if (DatabaseEncoding->encoding == PG_SQL_ASCII)
703 : : {
704 : : /*
705 : : * No conversion is possible, but we must still validate the data,
706 : : * because the client-side code might have done string escaping using
707 : : * the selected client_encoding. If the client encoding is ASCII-safe
708 : : * then we just do a straight validation under that encoding. For an
709 : : * ASCII-unsafe encoding we have a problem: we dare not pass such data
710 : : * to the parser but we have no way to convert it. We compromise by
711 : : * rejecting the data if it contains any non-ASCII characters.
712 : : */
5577 itagaki.takahiro@gma 713 [ + - + + ]: 163 : if (PG_VALID_BE_ENCODING(encoding))
[ + - + +
+ - ]
714 : 133 : (void) pg_verify_mbstr(encoding, s, len, false);
715 : : else
716 : : {
717 : : int i;
718 : :
7314 tgl@sss.pgh.pa.us 719 [ + + ]: 950 : for (i = 0; i < len; i++)
720 : : {
721 [ + - - + ]: 920 : if (s[i] == '\0' || IS_HIGHBIT_SET(s[i]))
7314 tgl@sss.pgh.pa.us 722 [ # # ]:UBC 0 : ereport(ERROR,
723 : : (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
724 : : errmsg("invalid byte value for encoding \"%s\": 0x%02x",
725 : : pg_enc2name_tbl[PG_SQL_ASCII].name,
726 : : (unsigned char) s[i])));
727 : : }
728 : : }
2678 peter@eisentraut.org 729 :CBC 163 : return unconstify(char *, s);
730 : : }
731 : :
732 : : /* Fast path if we can use cached conversion function */
4479 tgl@sss.pgh.pa.us 733 [ + - ]: 42 : if (encoding == ClientEncoding->encoding)
5577 itagaki.takahiro@gma 734 : 42 : return perform_default_encoding_conversion(s, len, true);
735 : :
736 : : /* General case ... will not work outside transactions */
2678 peter@eisentraut.org 737 :UBC 0 : return (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, s),
738 : : len,
739 : : encoding,
4479 tgl@sss.pgh.pa.us 740 : 0 : DatabaseEncoding->encoding);
741 : : }
742 : :
743 : : /*
744 : : * Convert server encoding to client encoding.
745 : : *
746 : : * See the notes about string conversion functions at the top of this file.
747 : : */
748 : : char *
7553 tgl@sss.pgh.pa.us 749 :CBC 25231180 : pg_server_to_client(const char *s, int len)
750 : : {
5577 itagaki.takahiro@gma 751 : 25231180 : return pg_server_to_any(s, len, ClientEncoding->encoding);
752 : : }
753 : :
754 : : /*
755 : : * Convert server encoding to any encoding.
756 : : *
757 : : * See the notes about string conversion functions at the top of this file.
758 : : */
759 : : char *
760 : 25253988 : pg_server_to_any(const char *s, int len, int encoding)
761 : : {
7314 tgl@sss.pgh.pa.us 762 [ + + ]: 25253988 : if (len <= 0)
2565 763 : 146127 : return unconstify(char *, s); /* empty string is always valid */
764 : :
5577 itagaki.takahiro@gma 765 [ + + + + ]: 25107861 : if (encoding == DatabaseEncoding->encoding ||
766 : : encoding == PG_SQL_ASCII)
2565 tgl@sss.pgh.pa.us 767 : 25107537 : return unconstify(char *, s); /* assume data is valid */
768 : :
4479 769 [ + + ]: 324 : if (DatabaseEncoding->encoding == PG_SQL_ASCII)
770 : : {
771 : : /* No conversion is possible, but we must validate the result */
772 : 82 : (void) pg_verify_mbstr(encoding, s, len, false);
2678 peter@eisentraut.org 773 : 82 : return unconstify(char *, s);
774 : : }
775 : :
776 : : /* Fast path if we can use cached conversion function */
4479 tgl@sss.pgh.pa.us 777 [ + + ]: 242 : if (encoding == ClientEncoding->encoding)
5577 itagaki.takahiro@gma 778 : 222 : return perform_default_encoding_conversion(s, len, false);
779 : :
780 : : /* General case ... will not work outside transactions */
2678 peter@eisentraut.org 781 :GBC 20 : return (char *) pg_do_encoding_conversion((unsigned char *) unconstify(char *, s),
782 : : len,
4479 tgl@sss.pgh.pa.us 783 : 20 : DatabaseEncoding->encoding,
784 : : encoding);
785 : : }
786 : :
787 : : /*
788 : : * Perform default encoding conversion using cached FmgrInfo. Since
789 : : * this function does not access database at all, it is safe to call
790 : : * outside transactions. If the conversion has not been set up by
791 : : * SetClientEncoding(), no conversion is performed.
792 : : */
793 : : static char *
4479 tgl@sss.pgh.pa.us 794 :CBC 264 : perform_default_encoding_conversion(const char *src, int len,
795 : : bool is_client_to_server)
796 : : {
797 : : char *result;
798 : : int src_encoding,
799 : : dest_encoding;
800 : : FmgrInfo *flinfo;
801 : :
8696 ishii@postgresql.org 802 [ + + ]: 264 : if (is_client_to_server)
803 : : {
804 : 42 : src_encoding = ClientEncoding->encoding;
805 : 42 : dest_encoding = DatabaseEncoding->encoding;
8610 tgl@sss.pgh.pa.us 806 : 42 : flinfo = ToServerConvProc;
807 : : }
808 : : else
809 : : {
8696 ishii@postgresql.org 810 : 222 : src_encoding = DatabaseEncoding->encoding;
811 : 222 : dest_encoding = ClientEncoding->encoding;
8610 tgl@sss.pgh.pa.us 812 : 222 : flinfo = ToClientConvProc;
813 : : }
814 : :
8696 ishii@postgresql.org 815 [ - + ]: 264 : if (flinfo == NULL)
2678 peter@eisentraut.org 816 :UBC 0 : return unconstify(char *, src);
817 : :
818 : : /*
819 : : * Allocate space for conversion result, being wary of integer overflow.
820 : : * See comments in pg_do_encoding_conversion.
821 : : */
2431 tgl@sss.pgh.pa.us 822 [ - + ]:CBC 264 : if ((Size) len >= (MaxAllocHugeSize / (Size) MAX_CONVERSION_GROWTH))
6942 tgl@sss.pgh.pa.us 823 [ # # ]:UBC 0 : ereport(ERROR,
824 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
825 : : errmsg("out of memory"),
826 : : errdetail("String of %d bytes is too long for encoding conversion.",
827 : : len)));
828 : :
829 : : result = (char *)
2431 tgl@sss.pgh.pa.us 830 :CBC 264 : MemoryContextAllocHuge(CurrentMemoryContext,
831 : 264 : (Size) len * MAX_CONVERSION_GROWTH + 1);
832 : :
1885 heikki.linnakangas@i 833 : 264 : FunctionCall6(flinfo,
834 : : Int32GetDatum(src_encoding),
835 : : Int32GetDatum(dest_encoding),
836 : : CStringGetDatum(src),
837 : : CStringGetDatum(result),
838 : : Int32GetDatum(len),
839 : : BoolGetDatum(false));
840 : :
841 : : /*
842 : : * Release extra space if there might be a lot --- see comments in
843 : : * pg_do_encoding_conversion.
844 : : */
2431 tgl@sss.pgh.pa.us 845 [ - + ]: 264 : if (len > 1000000)
846 : : {
2431 tgl@sss.pgh.pa.us 847 :UBC 0 : Size resultlen = strlen(result);
848 : :
849 [ # # ]: 0 : if (resultlen >= MaxAllocSize)
850 [ # # ]: 0 : ereport(ERROR,
851 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
852 : : errmsg("out of memory"),
853 : : errdetail("String of %d bytes is too long for encoding conversion.",
854 : : len)));
855 : :
856 : 0 : result = (char *) repalloc(result, resultlen + 1);
857 : : }
858 : :
8696 ishii@postgresql.org 859 :CBC 264 : return result;
860 : : }
861 : :
862 : : /*
863 : : * Convert a single Unicode code point into a string in the server encoding.
864 : : *
865 : : * The code point given by "c" is converted and stored at *s, which must
866 : : * have at least MAX_UNICODE_EQUIVALENT_STRING+1 bytes available.
867 : : * The output will have a trailing '\0'. Throws error if the conversion
868 : : * cannot be performed.
869 : : *
870 : : * Note that this relies on having previously looked up any required
871 : : * conversion function. That's partly for speed but mostly because the parser
872 : : * may call this outside any transaction, or in an aborted transaction.
873 : : */
874 : : void
213 jdavis@postgresql.or 875 :GNC 687 : pg_unicode_to_server(char32_t c, unsigned char *s)
876 : : {
877 : : unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1];
878 : : int c_as_utf8_len;
879 : : int server_encoding;
880 : :
881 : : /*
882 : : * Complain if invalid Unicode code point. The choice of errcode here is
883 : : * debatable, but really our caller should have checked this anyway.
884 : : */
2276 tgl@sss.pgh.pa.us 885 [ - + ]:CBC 687 : if (!is_valid_unicode_codepoint(c))
2276 tgl@sss.pgh.pa.us 886 [ # # ]:UBC 0 : ereport(ERROR,
887 : : (errcode(ERRCODE_SYNTAX_ERROR),
888 : : errmsg("invalid Unicode code point")));
889 : :
890 : : /* Otherwise, if it's in ASCII range, conversion is trivial */
2276 tgl@sss.pgh.pa.us 891 [ + + ]:CBC 687 : if (c <= 0x7F)
892 : : {
893 : 226 : s[0] = (unsigned char) c;
894 : 226 : s[1] = '\0';
895 : 687 : return;
896 : : }
897 : :
898 : : /* If the server encoding is UTF-8, we just need to reformat the code */
899 : 461 : server_encoding = GetDatabaseEncoding();
900 [ + - ]: 461 : if (server_encoding == PG_UTF8)
901 : : {
902 : 461 : unicode_to_utf8(c, s);
903 : 461 : s[pg_utf_mblen(s)] = '\0';
904 : 461 : return;
905 : : }
906 : :
907 : : /* For all other cases, we must have a conversion function available */
2276 tgl@sss.pgh.pa.us 908 [ # # ]:UBC 0 : if (Utf8ToServerConvProc == NULL)
909 [ # # ]: 0 : ereport(ERROR,
910 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
911 : : errmsg("conversion between %s and %s is not supported",
912 : : pg_enc2name_tbl[PG_UTF8].name,
913 : : GetDatabaseEncodingName())));
914 : :
915 : : /* Construct UTF-8 source string */
916 : 0 : unicode_to_utf8(c, c_as_utf8);
917 : 0 : c_as_utf8_len = pg_utf_mblen(c_as_utf8);
918 : 0 : c_as_utf8[c_as_utf8_len] = '\0';
919 : :
920 : : /* Convert, or throw error if we can't */
1885 heikki.linnakangas@i 921 : 0 : FunctionCall6(Utf8ToServerConvProc,
922 : : Int32GetDatum(PG_UTF8),
923 : : Int32GetDatum(server_encoding),
924 : : CStringGetDatum((char *) c_as_utf8),
925 : : CStringGetDatum((char *) s),
926 : : Int32GetDatum(c_as_utf8_len),
927 : : BoolGetDatum(false));
928 : : }
929 : :
930 : : /*
931 : : * Convert a single Unicode code point into a string in the server encoding.
932 : : *
933 : : * Same as pg_unicode_to_server(), except that we don't throw errors,
934 : : * but simply return false on conversion failure.
935 : : */
936 : : bool
213 jdavis@postgresql.or 937 :GNC 60 : pg_unicode_to_server_noerror(char32_t c, unsigned char *s)
938 : : {
939 : : unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1];
940 : : int c_as_utf8_len;
941 : : int converted_len;
942 : : int server_encoding;
943 : :
944 : : /* Fail if invalid Unicode code point */
1266 tgl@sss.pgh.pa.us 945 [ - + ]:CBC 60 : if (!is_valid_unicode_codepoint(c))
1266 tgl@sss.pgh.pa.us 946 :UBC 0 : return false;
947 : :
948 : : /* Otherwise, if it's in ASCII range, conversion is trivial */
1266 tgl@sss.pgh.pa.us 949 [ + + ]:CBC 60 : if (c <= 0x7F)
950 : : {
951 : 17 : s[0] = (unsigned char) c;
952 : 17 : s[1] = '\0';
953 : 17 : return true;
954 : : }
955 : :
956 : : /* If the server encoding is UTF-8, we just need to reformat the code */
957 : 43 : server_encoding = GetDatabaseEncoding();
958 [ + - ]: 43 : if (server_encoding == PG_UTF8)
959 : : {
960 : 43 : unicode_to_utf8(c, s);
961 : 43 : s[pg_utf_mblen(s)] = '\0';
962 : 43 : return true;
963 : : }
964 : :
965 : : /* For all other cases, we must have a conversion function available */
1266 tgl@sss.pgh.pa.us 966 [ # # ]:UBC 0 : if (Utf8ToServerConvProc == NULL)
967 : 0 : return false;
968 : :
969 : : /* Construct UTF-8 source string */
970 : 0 : unicode_to_utf8(c, c_as_utf8);
971 : 0 : c_as_utf8_len = pg_utf_mblen(c_as_utf8);
972 : 0 : c_as_utf8[c_as_utf8_len] = '\0';
973 : :
974 : : /* Convert, but without throwing error if we can't */
975 : 0 : converted_len = DatumGetInt32(FunctionCall6(Utf8ToServerConvProc,
976 : : Int32GetDatum(PG_UTF8),
977 : : Int32GetDatum(server_encoding),
978 : : CStringGetDatum((char *) c_as_utf8),
979 : : CStringGetDatum((char *) s),
980 : : Int32GetDatum(c_as_utf8_len),
981 : : BoolGetDatum(true)));
982 : :
983 : : /* Conversion was successful iff it consumed the whole input */
984 : 0 : return (converted_len == c_as_utf8_len);
985 : : }
986 : :
987 : :
988 : : /* convert a multibyte string to a wchar */
989 : : int
7553 990 : 0 : pg_mb2wchar(const char *from, pg_wchar *to)
991 : : {
3187 peter_e@gmx.net 992 : 0 : return pg_wchar_table[DatabaseEncoding->encoding].mb2wchar_with_len((const unsigned char *) from, to, strlen(from));
993 : : }
994 : :
995 : : /* convert a multibyte string to a wchar with a limited length */
996 : : int
7553 tgl@sss.pgh.pa.us 997 :CBC 6897418 : pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
998 : : {
3187 peter_e@gmx.net 999 : 6897418 : return pg_wchar_table[DatabaseEncoding->encoding].mb2wchar_with_len((const unsigned char *) from, to, len);
1000 : : }
1001 : :
1002 : : /* same, with any encoding */
1003 : : int
7097 tgl@sss.pgh.pa.us 1004 : 12373 : pg_encoding_mb2wchar_with_len(int encoding,
1005 : : const char *from, pg_wchar *to, int len)
1006 : : {
3187 peter_e@gmx.net 1007 : 12373 : return pg_wchar_table[encoding].mb2wchar_with_len((const unsigned char *) from, to, len);
1008 : : }
1009 : :
1010 : : /* convert a wchar string to a multibyte */
1011 : : int
5078 rhaas@postgresql.org 1012 :UBC 0 : pg_wchar2mb(const pg_wchar *from, char *to)
1013 : : {
3187 peter_e@gmx.net 1014 : 0 : return pg_wchar_table[DatabaseEncoding->encoding].wchar2mb_with_len(from, (unsigned char *) to, pg_wchar_strlen(from));
1015 : : }
1016 : :
1017 : : /* convert a wchar string to a multibyte with a limited length */
1018 : : int
5078 rhaas@postgresql.org 1019 :CBC 579775 : pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len)
1020 : : {
3187 peter_e@gmx.net 1021 : 579775 : return pg_wchar_table[DatabaseEncoding->encoding].wchar2mb_with_len(from, (unsigned char *) to, len);
1022 : : }
1023 : :
1024 : : /* same, with any encoding */
1025 : : int
5078 rhaas@postgresql.org 1026 : 116 : pg_encoding_wchar2mb_with_len(int encoding,
1027 : : const pg_wchar *from, char *to, int len)
1028 : : {
3187 peter_e@gmx.net 1029 : 116 : return pg_wchar_table[encoding].wchar2mb_with_len(from, (unsigned char *) to, len);
1030 : : }
1031 : :
1032 : : /*
1033 : : * Returns the byte length of a multibyte character sequence in a
1034 : : * null-terminated string. Raises an illegal byte sequence error if the
1035 : : * sequence would hit a null terminator.
1036 : : *
1037 : : * The caller is expected to have checked for a terminator at *mbstr == 0
1038 : : * before calling, but some callers want 1 in that case, so this function
1039 : : * continues that tradition.
1040 : : *
1041 : : * This must only be used for strings that have a null-terminator to enable
1042 : : * bounds detection.
1043 : : */
1044 : : int
143 tmunro@postgresql.or 1045 : 2945805 : pg_mblen_cstr(const char *mbstr)
1046 : : {
1047 : 2945805 : int length = pg_wchar_table[DatabaseEncoding->encoding].mblen((const unsigned char *) mbstr);
1048 : :
1049 : : /*
1050 : : * The .mblen functions return 1 when given a pointer to a terminator.
1051 : : * Some callers depend on that, so we tolerate it for now. Well-behaved
1052 : : * callers check the leading byte for a terminator *before* calling.
1053 : : */
1054 [ + + ]: 2958229 : for (int i = 1; i < length; ++i)
1055 [ + + ]: 12428 : if (unlikely(mbstr[i] == 0))
1056 : 4 : report_invalid_encoding_db(mbstr, length, i);
1057 : :
1058 : : /*
1059 : : * String should be NUL-terminated, but checking that would make typical
1060 : : * callers O(N^2), tripling Valgrind check-world time. Unless
1061 : : * VALGRIND_EXPENSIVE, check 1 byte after each actual character. (If we
1062 : : * found a character, not a terminator, the next byte must be a terminator
1063 : : * or the start of the next character.) If the caller iterates the whole
1064 : : * string, the last call will diagnose a missing terminator.
1065 : : */
1066 : 2945801 : if (mbstr[0] != '\0')
1067 : : {
1068 : : #ifdef VALGRIND_EXPENSIVE
1069 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr, strlen(mbstr));
1070 : : #else
1071 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr + length, 1);
1072 : : #endif
1073 : : }
1074 : :
1075 : 2945801 : return length;
1076 : : }
1077 : :
1078 : : /*
1079 : : * Returns the byte length of a multibyte character sequence bounded by a range
1080 : : * [mbstr, end) of at least one byte in size. Raises an illegal byte sequence
1081 : : * error if the sequence would exceed the range.
1082 : : */
1083 : : int
1084 : 3569100 : pg_mblen_range(const char *mbstr, const char *end)
1085 : : {
1086 : 3569100 : int length = pg_wchar_table[DatabaseEncoding->encoding].mblen((const unsigned char *) mbstr);
1087 : :
1088 [ - + ]: 3569100 : Assert(end > mbstr);
1089 : :
105 noah@leadboat.com 1090 [ + + ]: 3569100 : if (unlikely(mbstr + length > end))
1091 : 8 : report_invalid_encoding_db(mbstr, length, end - mbstr);
1092 : :
1093 : : #ifdef VALGRIND_EXPENSIVE
1094 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr, end - mbstr);
1095 : : #else
1096 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr, length);
1097 : : #endif
1098 : :
143 tmunro@postgresql.or 1099 : 3569092 : return length;
1100 : : }
1101 : :
1102 : : /*
1103 : : * Returns the byte length of a multibyte character sequence bounded by a range
1104 : : * extending for 'limit' bytes, which must be at least one. Raises an illegal
1105 : : * byte sequence error if the sequence would exceed the range.
1106 : : */
1107 : : int
1108 : 38113365 : pg_mblen_with_len(const char *mbstr, int limit)
1109 : : {
1110 : 38113365 : int length = pg_wchar_table[DatabaseEncoding->encoding].mblen((const unsigned char *) mbstr);
1111 : :
1112 [ - + ]: 38113365 : Assert(limit >= 1);
1113 : :
105 noah@leadboat.com 1114 [ + + ]: 38113365 : if (unlikely(length > limit))
1115 : 16 : report_invalid_encoding_db(mbstr, length, limit);
1116 : :
1117 : : #ifdef VALGRIND_EXPENSIVE
1118 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr, limit);
1119 : : #else
1120 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr, length);
1121 : : #endif
1122 : :
143 tmunro@postgresql.or 1123 : 38113349 : return length;
1124 : : }
1125 : :
1126 : :
1127 : : /*
1128 : : * Returns the length of a multibyte character sequence, without any
1129 : : * validation of bounds.
1130 : : *
1131 : : * PLEASE NOTE: This function can only be used safely if the caller has
1132 : : * already verified the input string, since otherwise there is a risk of
1133 : : * overrunning the buffer if the string is invalid. A prior call to a
1134 : : * pg_mbstrlen* function suffices.
1135 : : */
1136 : : int
1137 : 12800907 : pg_mblen_unbounded(const char *mbstr)
1138 : : {
1139 : 12800907 : int length = pg_wchar_table[DatabaseEncoding->encoding].mblen((const unsigned char *) mbstr);
1140 : :
1141 : : VALGRIND_CHECK_MEM_IS_DEFINED(mbstr, length);
1142 : :
1143 : 12800907 : return length;
1144 : : }
1145 : :
1146 : : /*
1147 : : * Historical name for pg_mblen_unbounded(). Should not be used and will be
1148 : : * removed in a later version.
1149 : : */
1150 : : int
7553 tgl@sss.pgh.pa.us 1151 :UBC 0 : pg_mblen(const char *mbstr)
1152 : : {
143 tmunro@postgresql.or 1153 : 0 : return pg_mblen_unbounded(mbstr);
1154 : : }
1155 : :
1156 : : /* returns the display length of a multibyte character */
1157 : : int
7553 tgl@sss.pgh.pa.us 1158 :CBC 7191 : pg_dsplen(const char *mbstr)
1159 : : {
3187 peter_e@gmx.net 1160 : 7191 : return pg_wchar_table[DatabaseEncoding->encoding].dsplen((const unsigned char *) mbstr);
1161 : : }
1162 : :
1163 : : /* returns the length (counted in wchars) of a multibyte string */
1164 : : int
7553 tgl@sss.pgh.pa.us 1165 : 76 : pg_mbstrlen(const char *mbstr)
1166 : : {
10133 bruce@momjian.us 1167 : 76 : int len = 0;
1168 : :
1169 : : /* optimization for single byte encoding */
8675 ishii@postgresql.org 1170 [ - + ]: 76 : if (pg_database_encoding_max_length() == 1)
7553 tgl@sss.pgh.pa.us 1171 :UBC 0 : return strlen(mbstr);
1172 : :
10133 bruce@momjian.us 1173 [ + + ]:CBC 300 : while (*mbstr)
1174 : : {
143 tmunro@postgresql.or 1175 : 224 : mbstr += pg_mblen_cstr(mbstr);
10133 bruce@momjian.us 1176 : 224 : len++;
1177 : : }
7444 neilc@samurai.com 1178 : 76 : return len;
1179 : : }
1180 : :
1181 : : /*
1182 : : * returns the length (counted in wchars) of a multibyte string
1183 : : * (stops at the first of "limit" or a NUL)
1184 : : */
1185 : : int
7553 tgl@sss.pgh.pa.us 1186 : 533283 : pg_mbstrlen_with_len(const char *mbstr, int limit)
1187 : : {
10133 bruce@momjian.us 1188 : 533283 : int len = 0;
1189 : :
1190 : : /* optimization for single byte encoding */
7629 tgl@sss.pgh.pa.us 1191 [ + + ]: 533283 : if (pg_database_encoding_max_length() == 1)
1192 : 200007 : return limit;
1193 : :
9214 1194 [ + + + + ]: 30328083 : while (limit > 0 && *mbstr)
1195 : : {
143 tmunro@postgresql.or 1196 : 29994811 : int l = pg_mblen_with_len(mbstr, limit);
1197 : :
10133 bruce@momjian.us 1198 : 29994807 : limit -= l;
1199 : 29994807 : mbstr += l;
1200 : 29994807 : len++;
1201 : : }
7444 neilc@samurai.com 1202 : 333272 : return len;
1203 : : }
1204 : :
1205 : : /*
1206 : : * returns the byte length of a multibyte string
1207 : : * (not necessarily NULL terminated)
1208 : : * that is no longer than limit.
1209 : : * this function does not break multibyte character boundary.
1210 : : */
1211 : : int
7553 tgl@sss.pgh.pa.us 1212 : 196333 : pg_mbcliplen(const char *mbstr, int len, int limit)
1213 : : {
6355 1214 : 196333 : return pg_encoding_mbcliplen(DatabaseEncoding->encoding, mbstr,
1215 : : len, limit);
1216 : : }
1217 : :
1218 : : /*
1219 : : * pg_mbcliplen with specified encoding; string must be valid in encoding
1220 : : */
1221 : : int
1222 : 196333 : pg_encoding_mbcliplen(int encoding, const char *mbstr,
1223 : : int len, int limit)
1224 : : {
1225 : : mblen_converter mblen_fn;
10109 bruce@momjian.us 1226 : 196333 : int clen = 0;
1227 : : int l;
1228 : :
1229 : : /* optimization for single byte encoding */
6355 tgl@sss.pgh.pa.us 1230 [ + + ]: 196333 : if (pg_encoding_max_length(encoding) == 1)
8675 ishii@postgresql.org 1231 : 21073 : return cliplen(mbstr, len, limit);
1232 : :
6355 tgl@sss.pgh.pa.us 1233 : 175260 : mblen_fn = pg_wchar_table[encoding].mblen;
1234 : :
9214 1235 [ + + + - ]: 1843823 : while (len > 0 && *mbstr)
1236 : : {
6355 1237 : 1760855 : l = (*mblen_fn) ((const unsigned char *) mbstr);
9867 bruce@momjian.us 1238 [ + + ]: 1760855 : if ((clen + l) > limit)
10109 1239 : 73 : break;
1240 : 1760782 : clen += l;
9867 1241 [ + + ]: 1760782 : if (clen == limit)
10109 1242 : 92219 : break;
1243 : 1668563 : len -= l;
1244 : 1668563 : mbstr += l;
1245 : : }
7444 neilc@samurai.com 1246 : 175260 : return clen;
1247 : : }
1248 : :
1249 : : /*
1250 : : * Similar to pg_mbcliplen except the limit parameter specifies the
1251 : : * character length, not the byte length.
1252 : : */
1253 : : int
7553 tgl@sss.pgh.pa.us 1254 : 368 : pg_mbcharcliplen(const char *mbstr, int len, int limit)
1255 : : {
9085 ishii@postgresql.org 1256 : 368 : int clen = 0;
1257 : 368 : int nch = 0;
1258 : : int l;
1259 : :
1260 : : /* optimization for single byte encoding */
8675 1261 [ - + ]: 368 : if (pg_database_encoding_max_length() == 1)
8675 ishii@postgresql.org 1262 :UBC 0 : return cliplen(mbstr, len, limit);
1263 : :
9085 ishii@postgresql.org 1264 [ + + + - ]:CBC 1603 : while (len > 0 && *mbstr)
1265 : : {
143 tmunro@postgresql.or 1266 : 1591 : l = pg_mblen_with_len(mbstr, len);
9085 ishii@postgresql.org 1267 : 1591 : nch++;
1268 [ + + ]: 1591 : if (nch > limit)
1269 : 356 : break;
1270 : 1235 : clen += l;
1271 : 1235 : len -= l;
1272 : 1235 : mbstr += l;
1273 : : }
7444 neilc@samurai.com 1274 : 368 : return clen;
1275 : : }
1276 : :
1277 : : /* mbcliplen for any single-byte encoding */
1278 : : static int
6355 tgl@sss.pgh.pa.us 1279 : 21073 : cliplen(const char *str, int len, int limit)
1280 : : {
1281 : 21073 : int l = 0;
1282 : :
1283 : 21073 : len = Min(len, limit);
1284 [ + + + - ]: 166774 : while (l < len && str[l])
1285 : 145701 : l++;
1286 : 21073 : return l;
1287 : : }
1288 : :
1289 : : void
10172 scrappy@hub.org 1290 : 16987 : SetDatabaseEncoding(int encoding)
1291 : : {
9032 ishii@postgresql.org 1292 [ + - - + ]: 16987 : if (!PG_VALID_BE_ENCODING(encoding))
[ + - + -
- + ]
7100 peter_e@gmx.net 1293 [ # # ]:UBC 0 : elog(ERROR, "invalid database encoding: %d", encoding);
1294 : :
8983 bruce@momjian.us 1295 :CBC 16987 : DatabaseEncoding = &pg_enc2name_tbl[encoding];
9032 ishii@postgresql.org 1296 [ - + ]: 16987 : Assert(DatabaseEncoding->encoding == encoding);
6292 alvherre@alvh.no-ip. 1297 : 16987 : }
1298 : :
1299 : : void
4721 noah@leadboat.com 1300 : 19163 : SetMessageEncoding(int encoding)
1301 : : {
1302 : : /* Some calls happen before we can elog()! */
1303 [ + - - + ]: 19163 : Assert(PG_VALID_ENCODING(encoding));
[ + - + -
- + ]
1304 : :
1305 : 19163 : MessageEncoding = &pg_enc2name_tbl[encoding];
1306 [ - + ]: 19163 : Assert(MessageEncoding->encoding == encoding);
1307 : 19163 : }
1308 : :
1309 : : #ifdef ENABLE_NLS
1310 : : /*
1311 : : * Make one bind_textdomain_codeset() call, translating a pg_enc to a gettext
1312 : : * codeset. Can fail for gettext-internal causes like out-of-memory.
1313 : : */
1314 : : static bool
1315 : 1638 : raw_pg_bind_textdomain_codeset(const char *domainname, int encoding)
1316 : : {
1317 : 1638 : bool elog_ok = (CurrentMemoryContext != NULL);
1318 : :
820 michael@paquier.xyz 1319 [ + - + - : 1638 : if (!PG_VALID_ENCODING(encoding) || pg_enc2gettext_tbl[encoding] == NULL)
- + ][ + -
+ - + - -
+ ]
820 michael@paquier.xyz 1320 :UBC 0 : return false;
1321 : :
820 michael@paquier.xyz 1322 [ + - ]:CBC 1638 : if (bind_textdomain_codeset(domainname,
1323 : : pg_enc2gettext_tbl[encoding]) != NULL)
1324 : 1638 : return true;
1325 : :
820 michael@paquier.xyz 1326 [ # # ]:UBC 0 : if (elog_ok)
1327 [ # # ]: 0 : elog(LOG, "bind_textdomain_codeset failed");
1328 : : else
1329 : 0 : write_stderr("bind_textdomain_codeset failed");
1330 : :
4721 noah@leadboat.com 1331 : 0 : return false;
1332 : : }
1333 : :
1334 : : /*
1335 : : * Bind a gettext message domain to the codeset corresponding to the database
1336 : : * encoding. For SQL_ASCII, instead bind to the codeset implied by LC_CTYPE.
1337 : : * Return the MessageEncoding implied by the new settings.
1338 : : *
1339 : : * On most platforms, gettext defaults to the codeset implied by LC_CTYPE.
1340 : : * When that matches the database encoding, we don't need to do anything. In
1341 : : * CREATE DATABASE, we enforce or trust that the locale's codeset matches the
1342 : : * database encoding, except for the C locale. (On Windows, we also permit a
1343 : : * discrepancy under the UTF8 encoding.) For the C locale, explicitly bind
1344 : : * gettext to the right codeset.
1345 : : *
1346 : : * On Windows, gettext defaults to the Windows ANSI code page. This is a
1347 : : * convenient departure for software that passes the strings to Windows ANSI
1348 : : * APIs, but we don't do that. Compel gettext to use database encoding or,
1349 : : * failing that, the LC_CTYPE encoding as it would on other platforms.
1350 : : *
1351 : : * This function is called before elog() and palloc() are usable.
1352 : : */
1353 : : int
4721 noah@leadboat.com 1354 :CBC 21643 : pg_bind_textdomain_codeset(const char *domainname)
1355 : : {
1356 : 21643 : bool elog_ok = (CurrentMemoryContext != NULL);
1357 : 21643 : int encoding = GetDatabaseEncoding();
1358 : : int new_msgenc;
1359 : :
1360 : : #ifndef WIN32
1361 : 21643 : const char *ctype = setlocale(LC_CTYPE, NULL);
1362 : :
1363 [ + + - + ]: 21643 : if (pg_strcasecmp(ctype, "C") == 0 || pg_strcasecmp(ctype, "POSIX") == 0)
1364 : : #endif
1365 [ + + + - ]: 3671 : if (encoding != PG_SQL_ASCII &&
1366 : 1638 : raw_pg_bind_textdomain_codeset(domainname, encoding))
1367 : 1638 : return encoding;
1368 : :
1369 : 20005 : new_msgenc = pg_get_encoding_from_locale(NULL, elog_ok);
1370 [ - + ]: 20005 : if (new_msgenc < 0)
4721 noah@leadboat.com 1371 :UBC 0 : new_msgenc = PG_SQL_ASCII;
1372 : :
1373 : : #ifdef WIN32
1374 : : if (!raw_pg_bind_textdomain_codeset(domainname, new_msgenc))
1375 : : /* On failure, the old message encoding remains valid. */
1376 : : return GetMessageEncoding();
1377 : : #endif
1378 : :
4721 noah@leadboat.com 1379 :CBC 20005 : return new_msgenc;
1380 : : }
1381 : : #endif
1382 : :
1383 : : /*
1384 : : * The database encoding, also called the server encoding, represents the
1385 : : * encoding of data stored in text-like data types. Affected types include
1386 : : * cstring, text, varchar, name, xml, and json.
1387 : : */
1388 : : int
9017 tgl@sss.pgh.pa.us 1389 : 5650738 : GetDatabaseEncoding(void)
1390 : : {
7444 neilc@samurai.com 1391 : 5650738 : return DatabaseEncoding->encoding;
1392 : : }
1393 : :
1394 : : const char *
9017 tgl@sss.pgh.pa.us 1395 : 35823 : GetDatabaseEncodingName(void)
1396 : : {
7444 neilc@samurai.com 1397 : 35823 : return DatabaseEncoding->name;
1398 : : }
1399 : :
1400 : : Datum
9482 tgl@sss.pgh.pa.us 1401 : 6154 : getdatabaseencoding(PG_FUNCTION_ARGS)
1402 : : {
9032 ishii@postgresql.org 1403 : 6154 : return DirectFunctionCall1(namein, CStringGetDatum(DatabaseEncoding->name));
1404 : : }
1405 : :
1406 : : Datum
8996 ishii@postgresql.org 1407 :UBC 0 : pg_client_encoding(PG_FUNCTION_ARGS)
1408 : : {
1409 : 0 : return DirectFunctionCall1(namein, CStringGetDatum(ClientEncoding->name));
1410 : : }
1411 : :
1412 : : Datum
2326 tgl@sss.pgh.pa.us 1413 :CBC 6110 : PG_char_to_encoding(PG_FUNCTION_ARGS)
1414 : : {
1415 : 6110 : Name s = PG_GETARG_NAME(0);
1416 : :
1417 : 6110 : PG_RETURN_INT32(pg_char_to_encoding(NameStr(*s)));
1418 : : }
1419 : :
1420 : : Datum
1421 : 2382 : PG_encoding_to_char(PG_FUNCTION_ARGS)
1422 : : {
1423 : 2382 : int32 encoding = PG_GETARG_INT32(0);
1424 : 2382 : const char *encoding_name = pg_encoding_to_char(encoding);
1425 : :
1426 : 2382 : return DirectFunctionCall1(namein, CStringGetDatum(encoding_name));
1427 : : }
1428 : :
1429 : : /*
1430 : : * gettext() returns messages in this encoding. This often matches the
1431 : : * database encoding, but it differs for SQL_ASCII databases, for processes
1432 : : * not attached to a database.
1433 : : */
1434 : : int
4721 noah@leadboat.com 1435 :UBC 0 : GetMessageEncoding(void)
1436 : : {
1437 : 0 : return MessageEncoding->encoding;
1438 : : }
1439 : :
1440 : :
1441 : : /*
1442 : : * Generic character incrementer function.
1443 : : *
1444 : : * Not knowing anything about the properties of the encoding in use, we just
1445 : : * keep incrementing the last byte until we get a validly-encoded result,
1446 : : * or we run out of values to try. We don't bother to try incrementing
1447 : : * higher-order bytes, so there's no growth in runtime for wider characters.
1448 : : * (If we did try to do that, we'd need to consider the likelihood that 255
1449 : : * is not a valid final byte in the encoding.)
1450 : : */
1451 : : static bool
2326 tgl@sss.pgh.pa.us 1452 :CBC 48 : pg_generic_charinc(unsigned char *charptr, int len)
1453 : : {
1454 : 48 : unsigned char *lastbyte = charptr + len - 1;
1455 : : mbchar_verifier mbverify;
1456 : :
1457 : : /* We can just invoke the character verifier directly. */
1948 heikki.linnakangas@i 1458 : 48 : mbverify = pg_wchar_table[GetDatabaseEncoding()].mbverifychar;
1459 : :
2326 tgl@sss.pgh.pa.us 1460 [ + - ]: 48 : while (*lastbyte < (unsigned char) 255)
1461 : : {
1462 : 48 : (*lastbyte)++;
1463 [ + - ]: 48 : if ((*mbverify) (charptr, len) == len)
1464 : 48 : return true;
1465 : : }
1466 : :
2326 tgl@sss.pgh.pa.us 1467 :UBC 0 : return false;
1468 : : }
1469 : :
1470 : : /*
1471 : : * UTF-8 character incrementer function.
1472 : : *
1473 : : * For a one-byte character less than 0x7F, we just increment the byte.
1474 : : *
1475 : : * For a multibyte character, every byte but the first must fall between 0x80
1476 : : * and 0xBF; and the first byte must be between 0xC0 and 0xF4. We increment
1477 : : * the last byte that's not already at its maximum value. If we can't find a
1478 : : * byte that's less than the maximum allowable value, we simply fail. We also
1479 : : * need some special-case logic to skip regions used for surrogate pair
1480 : : * handling, as those should not occur in valid UTF-8.
1481 : : *
1482 : : * Note that we don't reset lower-order bytes back to their minimums, since
1483 : : * we can't afford to make an exhaustive search (see make_greater_string).
1484 : : */
1485 : : static bool
2326 tgl@sss.pgh.pa.us 1486 :CBC 2371 : pg_utf8_increment(unsigned char *charptr, int length)
1487 : : {
1488 : : unsigned char a;
1489 : : unsigned char limit;
1490 : :
1491 [ - - - - : 2371 : switch (length)
+ ]
1492 : : {
2326 tgl@sss.pgh.pa.us 1493 :UBC 0 : default:
1494 : : /* reject lengths 5 and 6 for now */
1495 : 0 : return false;
1496 : 0 : case 4:
1497 : 0 : a = charptr[3];
1498 [ # # ]: 0 : if (a < 0xBF)
1499 : : {
1500 : 0 : charptr[3]++;
1501 : 0 : break;
1502 : : }
1503 : : pg_fallthrough;
1504 : : case 3:
1505 : 0 : a = charptr[2];
1506 [ # # ]: 0 : if (a < 0xBF)
1507 : : {
1508 : 0 : charptr[2]++;
1509 : 0 : break;
1510 : : }
1511 : : pg_fallthrough;
1512 : : case 2:
1513 : 0 : a = charptr[1];
1514 [ # # # ]: 0 : switch (*charptr)
1515 : : {
1516 : 0 : case 0xED:
1517 : 0 : limit = 0x9F;
1518 : 0 : break;
1519 : 0 : case 0xF4:
1520 : 0 : limit = 0x8F;
1521 : 0 : break;
1522 : 0 : default:
1523 : 0 : limit = 0xBF;
1524 : 0 : break;
1525 : : }
1526 [ # # ]: 0 : if (a < limit)
1527 : : {
1528 : 0 : charptr[1]++;
1529 : 0 : break;
1530 : : }
1531 : : pg_fallthrough;
1532 : : case 1:
2326 tgl@sss.pgh.pa.us 1533 :CBC 2371 : a = *charptr;
1534 [ + - + - : 2371 : if (a == 0x7F || a == 0xDF || a == 0xEF || a == 0xF4)
+ - - + ]
2326 tgl@sss.pgh.pa.us 1535 :UBC 0 : return false;
2326 tgl@sss.pgh.pa.us 1536 :CBC 2371 : charptr[0]++;
1537 : 2371 : break;
1538 : : }
1539 : :
1540 : 2371 : return true;
1541 : : }
1542 : :
1543 : : /*
1544 : : * EUC-JP character incrementer function.
1545 : : *
1546 : : * If the sequence starts with SS2 (0x8e), it must be a two-byte sequence
1547 : : * representing JIS X 0201 characters with the second byte ranging between
1548 : : * 0xa1 and 0xdf. We just increment the last byte if it's less than 0xdf,
1549 : : * and otherwise rewrite the whole sequence to 0xa1 0xa1.
1550 : : *
1551 : : * If the sequence starts with SS3 (0x8f), it must be a three-byte sequence
1552 : : * in which the last two bytes range between 0xa1 and 0xfe. The last byte
1553 : : * is incremented if possible, otherwise the second-to-last byte.
1554 : : *
1555 : : * If the sequence starts with a value other than the above and its MSB
1556 : : * is set, it must be a two-byte sequence representing JIS X 0208 characters
1557 : : * with both bytes ranging between 0xa1 and 0xfe. The last byte is
1558 : : * incremented if possible, otherwise the second-to-last byte.
1559 : : *
1560 : : * Otherwise, the sequence is a single-byte ASCII character. It is
1561 : : * incremented up to 0x7f.
1562 : : */
1563 : : static bool
2326 tgl@sss.pgh.pa.us 1564 :UBC 0 : pg_eucjp_increment(unsigned char *charptr, int length)
1565 : : {
1566 : : unsigned char c1,
1567 : : c2;
1568 : : int i;
1569 : :
1570 : 0 : c1 = *charptr;
1571 : :
1572 [ # # # ]: 0 : switch (c1)
1573 : : {
1574 : 0 : case SS2: /* JIS X 0201 */
1575 [ # # ]: 0 : if (length != 2)
1576 : 0 : return false;
1577 : :
1578 : 0 : c2 = charptr[1];
1579 : :
1580 [ # # ]: 0 : if (c2 >= 0xdf)
1581 : 0 : charptr[0] = charptr[1] = 0xa1;
1582 [ # # ]: 0 : else if (c2 < 0xa1)
1583 : 0 : charptr[1] = 0xa1;
1584 : : else
1585 : 0 : charptr[1]++;
1586 : 0 : break;
1587 : :
1588 : 0 : case SS3: /* JIS X 0212 */
1589 [ # # ]: 0 : if (length != 3)
1590 : 0 : return false;
1591 : :
1592 [ # # ]: 0 : for (i = 2; i > 0; i--)
1593 : : {
1594 : 0 : c2 = charptr[i];
1595 [ # # ]: 0 : if (c2 < 0xa1)
1596 : : {
1597 : 0 : charptr[i] = 0xa1;
1598 : 0 : return true;
1599 : : }
1600 [ # # ]: 0 : else if (c2 < 0xfe)
1601 : : {
1602 : 0 : charptr[i]++;
1603 : 0 : return true;
1604 : : }
1605 : : }
1606 : :
1607 : : /* Out of 3-byte code region */
1608 : 0 : return false;
1609 : :
1610 : 0 : default:
1611 [ # # ]: 0 : if (IS_HIGHBIT_SET(c1)) /* JIS X 0208? */
1612 : : {
1613 [ # # ]: 0 : if (length != 2)
1614 : 0 : return false;
1615 : :
1616 [ # # ]: 0 : for (i = 1; i >= 0; i--)
1617 : : {
1618 : 0 : c2 = charptr[i];
1619 [ # # ]: 0 : if (c2 < 0xa1)
1620 : : {
1621 : 0 : charptr[i] = 0xa1;
1622 : 0 : return true;
1623 : : }
1624 [ # # ]: 0 : else if (c2 < 0xfe)
1625 : : {
1626 : 0 : charptr[i]++;
1627 : 0 : return true;
1628 : : }
1629 : : }
1630 : :
1631 : : /* Out of 2 byte code region */
1632 : 0 : return false;
1633 : : }
1634 : : else
1635 : : { /* ASCII, single byte */
1636 [ # # ]: 0 : if (c1 > 0x7e)
1637 : 0 : return false;
1638 : 0 : (*charptr)++;
1639 : : }
1640 : 0 : break;
1641 : : }
1642 : :
1643 : 0 : return true;
1644 : : }
1645 : :
1646 : : /*
1647 : : * get the character incrementer for the encoding for the current database
1648 : : */
1649 : : mbcharacter_incrementer
2326 tgl@sss.pgh.pa.us 1650 :CBC 2419 : pg_database_encoding_character_incrementer(void)
1651 : : {
1652 : : /*
1653 : : * Eventually it might be best to add a field to pg_wchar_table[], but for
1654 : : * now we just use a switch.
1655 : : */
1656 [ + - + ]: 2419 : switch (GetDatabaseEncoding())
1657 : : {
1658 : 2371 : case PG_UTF8:
1659 : 2371 : return pg_utf8_increment;
1660 : :
2326 tgl@sss.pgh.pa.us 1661 :UBC 0 : case PG_EUC_JP:
1662 : 0 : return pg_eucjp_increment;
1663 : :
2326 tgl@sss.pgh.pa.us 1664 :CBC 48 : default:
1665 : 48 : return pg_generic_charinc;
1666 : : }
1667 : : }
1668 : :
1669 : : /*
1670 : : * fetch maximum length of the encoding for the current database
1671 : : */
1672 : : int
1673 : 3678130 : pg_database_encoding_max_length(void)
1674 : : {
1675 : 3678130 : return pg_wchar_table[GetDatabaseEncoding()].maxmblen;
1676 : : }
1677 : :
1678 : : /*
1679 : : * Verify mbstr to make sure that it is validly encoded in the current
1680 : : * database encoding. Otherwise same as pg_verify_mbstr().
1681 : : */
1682 : : bool
1683 : 153663 : pg_verifymbstr(const char *mbstr, int len, bool noError)
1684 : : {
1948 heikki.linnakangas@i 1685 : 153663 : return pg_verify_mbstr(GetDatabaseEncoding(), mbstr, len, noError);
1686 : : }
1687 : :
1688 : : /*
1689 : : * Verify mbstr to make sure that it is validly encoded in the specified
1690 : : * encoding.
1691 : : */
1692 : : bool
2326 tgl@sss.pgh.pa.us 1693 : 1007358 : pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError)
1694 : : {
1695 : : int oklen;
1696 : :
1948 heikki.linnakangas@i 1697 [ + - - + ]: 1007358 : Assert(PG_VALID_ENCODING(encoding));
[ + - + -
- + ]
1698 : :
1699 : 1007358 : oklen = pg_wchar_table[encoding].mbverifystr((const unsigned char *) mbstr, len);
1700 [ + + ]: 1007358 : if (oklen != len)
1701 : : {
1702 [ - + ]: 10 : if (noError)
1948 heikki.linnakangas@i 1703 :UBC 0 : return false;
1948 heikki.linnakangas@i 1704 :CBC 10 : report_invalid_encoding(encoding, mbstr + oklen, len - oklen);
1705 : : }
1706 : 1007348 : return true;
1707 : : }
1708 : :
1709 : : /*
1710 : : * Verify mbstr to make sure that it is validly encoded in the specified
1711 : : * encoding.
1712 : : *
1713 : : * mbstr is not necessarily zero terminated; length of mbstr is
1714 : : * specified by len.
1715 : : *
1716 : : * If OK, return length of string in the encoding.
1717 : : * If a problem is found, return -1 when noError is
1718 : : * true; when noError is false, ereport() a descriptive message.
1719 : : *
1720 : : * Note: We cannot use the faster encoding-specific mbverifystr() function
1721 : : * here, because we need to count the number of characters in the string.
1722 : : */
1723 : : int
2326 tgl@sss.pgh.pa.us 1724 :UBC 0 : pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError)
1725 : : {
1726 : : mbchar_verifier mbverifychar;
1727 : : int mb_len;
1728 : :
1729 [ # # # # ]: 0 : Assert(PG_VALID_ENCODING(encoding));
[ # # # #
# # ]
1730 : :
1731 : : /*
1732 : : * In single-byte encodings, we need only reject nulls (\0).
1733 : : */
1734 [ # # ]: 0 : if (pg_encoding_max_length(encoding) <= 1)
1735 : : {
1736 : 0 : const char *nullpos = memchr(mbstr, 0, len);
1737 : :
1738 [ # # ]: 0 : if (nullpos == NULL)
1739 : 0 : return len;
1740 [ # # ]: 0 : if (noError)
1741 : 0 : return -1;
1742 : 0 : report_invalid_encoding(encoding, nullpos, 1);
1743 : : }
1744 : :
1745 : : /* fetch function pointer just once */
1948 heikki.linnakangas@i 1746 : 0 : mbverifychar = pg_wchar_table[encoding].mbverifychar;
1747 : :
2326 tgl@sss.pgh.pa.us 1748 : 0 : mb_len = 0;
1749 : :
1750 [ # # ]: 0 : while (len > 0)
1751 : : {
1752 : : int l;
1753 : :
1754 : : /* fast path for ASCII-subset characters */
1755 [ # # ]: 0 : if (!IS_HIGHBIT_SET(*mbstr))
1756 : : {
1757 [ # # ]: 0 : if (*mbstr != '\0')
1758 : : {
1759 : 0 : mb_len++;
1760 : 0 : mbstr++;
1761 : 0 : len--;
1762 : 0 : continue;
1763 : : }
1764 [ # # ]: 0 : if (noError)
1765 : 0 : return -1;
1766 : 0 : report_invalid_encoding(encoding, mbstr, len);
1767 : : }
1768 : :
1948 heikki.linnakangas@i 1769 : 0 : l = (*mbverifychar) ((const unsigned char *) mbstr, len);
1770 : :
2326 tgl@sss.pgh.pa.us 1771 [ # # ]: 0 : if (l < 0)
1772 : : {
1773 [ # # ]: 0 : if (noError)
1774 : 0 : return -1;
1775 : 0 : report_invalid_encoding(encoding, mbstr, len);
1776 : : }
1777 : :
1778 : 0 : mbstr += l;
1779 : 0 : len -= l;
1780 : 0 : mb_len++;
1781 : : }
1782 : 0 : return mb_len;
1783 : : }
1784 : :
1785 : : /*
1786 : : * check_encoding_conversion_args: check arguments of a conversion function
1787 : : *
1788 : : * "expected" arguments can be either an encoding ID or -1 to indicate that
1789 : : * the caller will check whether it accepts the ID.
1790 : : *
1791 : : * Note: the errors here are not really user-facing, so elog instead of
1792 : : * ereport seems sufficient. Also, we trust that the "expected" encoding
1793 : : * arguments are valid encoding IDs, but we don't trust the actuals.
1794 : : */
1795 : : void
2326 tgl@sss.pgh.pa.us 1796 :CBC 3346 : check_encoding_conversion_args(int src_encoding,
1797 : : int dest_encoding,
1798 : : int len,
1799 : : int expected_src_encoding,
1800 : : int expected_dest_encoding)
1801 : : {
1802 [ + - - + ]: 3346 : if (!PG_VALID_ENCODING(src_encoding))
[ + - + -
- + ]
2326 tgl@sss.pgh.pa.us 1803 [ # # ]:UBC 0 : elog(ERROR, "invalid source encoding ID: %d", src_encoding);
2326 tgl@sss.pgh.pa.us 1804 [ + + - + ]:CBC 3346 : if (src_encoding != expected_src_encoding && expected_src_encoding >= 0)
2326 tgl@sss.pgh.pa.us 1805 [ # # ]:UBC 0 : elog(ERROR, "expected source encoding \"%s\", but got \"%s\"",
1806 : : pg_enc2name_tbl[expected_src_encoding].name,
1807 : : pg_enc2name_tbl[src_encoding].name);
2326 tgl@sss.pgh.pa.us 1808 [ + - - + ]:CBC 3346 : if (!PG_VALID_ENCODING(dest_encoding))
[ + - + -
- + ]
2326 tgl@sss.pgh.pa.us 1809 [ # # ]:UBC 0 : elog(ERROR, "invalid destination encoding ID: %d", dest_encoding);
2326 tgl@sss.pgh.pa.us 1810 [ + + - + ]:CBC 3346 : if (dest_encoding != expected_dest_encoding && expected_dest_encoding >= 0)
2326 tgl@sss.pgh.pa.us 1811 [ # # ]:UBC 0 : elog(ERROR, "expected destination encoding \"%s\", but got \"%s\"",
1812 : : pg_enc2name_tbl[expected_dest_encoding].name,
1813 : : pg_enc2name_tbl[dest_encoding].name);
2326 tgl@sss.pgh.pa.us 1814 [ - + ]:CBC 3346 : if (len < 0)
2326 tgl@sss.pgh.pa.us 1815 [ # # ]:UBC 0 : elog(ERROR, "encoding conversion length must not be negative");
2326 tgl@sss.pgh.pa.us 1816 :CBC 3346 : }
1817 : :
1818 : : /*
1819 : : * report_invalid_encoding: complain about invalid multibyte character
1820 : : *
1821 : : * note: len is remaining length of string, not length of character;
1822 : : * len must be greater than zero (or we'd neglect initializing "buf").
1823 : : */
1824 : : void
1825 : 1626 : report_invalid_encoding(int encoding, const char *mbstr, int len)
1826 : : {
390 noah@leadboat.com 1827 : 1626 : int l = pg_encoding_mblen_or_incomplete(encoding, mbstr, len);
1828 : :
143 tmunro@postgresql.or 1829 : 1626 : report_invalid_encoding_int(encoding, mbstr, l, len);
1830 : : }
1831 : :
1832 : : static void
1833 : 1654 : report_invalid_encoding_int(int encoding, const char *mbstr, int mblen, int len)
1834 : : {
1835 : : char buf[8 * 5 + 1];
2326 tgl@sss.pgh.pa.us 1836 : 1654 : char *p = buf;
1837 : : int j,
1838 : : jlimit;
1839 : :
143 tmunro@postgresql.or 1840 : 1654 : jlimit = Min(mblen, len);
2326 tgl@sss.pgh.pa.us 1841 : 1654 : jlimit = Min(jlimit, 8); /* prevent buffer overrun */
1842 : :
1843 [ + + ]: 5180 : for (j = 0; j < jlimit; j++)
1844 : : {
1845 : 3526 : p += sprintf(p, "0x%02x", (unsigned char) mbstr[j]);
1846 [ + + ]: 3526 : if (j < jlimit - 1)
1847 : 1872 : p += sprintf(p, " ");
1848 : : }
1849 : :
1850 [ + - ]: 1654 : ereport(ERROR,
1851 : : (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
1852 : : errmsg("invalid byte sequence for encoding \"%s\": %s",
1853 : : pg_enc2name_tbl[encoding].name,
1854 : : buf)));
1855 : : }
1856 : :
1857 : : static void
143 tmunro@postgresql.or 1858 : 28 : report_invalid_encoding_db(const char *mbstr, int mblen, int len)
1859 : : {
1860 : 28 : report_invalid_encoding_int(GetDatabaseEncoding(), mbstr, mblen, len);
1861 : : }
1862 : :
1863 : : /*
1864 : : * report_untranslatable_char: complain about untranslatable character
1865 : : *
1866 : : * note: len is remaining length of string, not length of character;
1867 : : * len must be greater than zero (or we'd neglect initializing "buf").
1868 : : */
1869 : : void
2326 tgl@sss.pgh.pa.us 1870 : 384 : report_untranslatable_char(int src_encoding, int dest_encoding,
1871 : : const char *mbstr, int len)
1872 : : {
1873 : : int l;
1874 : : char buf[8 * 5 + 1];
1875 : 384 : char *p = buf;
1876 : : int j,
1877 : : jlimit;
1878 : :
1879 : : /*
1880 : : * We probably could use plain pg_encoding_mblen(), because
1881 : : * gb18030_to_utf8() verifies before it converts. All conversions should.
1882 : : * For src_encoding!=GB18030, len>0 meets pg_encoding_mblen() needs. Even
1883 : : * so, be defensive, since a buggy conversion might pass invalid data.
1884 : : * This is not a performance-critical path.
1885 : : */
390 noah@leadboat.com 1886 : 384 : l = pg_encoding_mblen_or_incomplete(src_encoding, mbstr, len);
2326 tgl@sss.pgh.pa.us 1887 : 384 : jlimit = Min(l, len);
1888 : 384 : jlimit = Min(jlimit, 8); /* prevent buffer overrun */
1889 : :
1890 [ + + ]: 1488 : for (j = 0; j < jlimit; j++)
1891 : : {
1892 : 1104 : p += sprintf(p, "0x%02x", (unsigned char) mbstr[j]);
1893 [ + + ]: 1104 : if (j < jlimit - 1)
1894 : 720 : p += sprintf(p, " ");
1895 : : }
1896 : :
1897 [ + - ]: 384 : ereport(ERROR,
1898 : : (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
1899 : : errmsg("character with byte sequence %s in encoding \"%s\" has no equivalent in encoding \"%s\"",
1900 : : buf,
1901 : : pg_enc2name_tbl[src_encoding].name,
1902 : : pg_enc2name_tbl[dest_encoding].name)));
1903 : : }
1904 : :
1905 : :
1906 : : #ifdef WIN32
1907 : : /*
1908 : : * Convert from MessageEncoding to a palloc'ed, null-terminated utf16
1909 : : * string. The character length is also passed to utf16len if not
1910 : : * null. Returns NULL iff failed. Before MessageEncoding initialization, "str"
1911 : : * should be ASCII-only; this will function as though MessageEncoding is UTF8.
1912 : : */
1913 : : WCHAR *
1914 : : pgwin32_message_to_UTF16(const char *str, int len, int *utf16len)
1915 : : {
1916 : : int msgenc = GetMessageEncoding();
1917 : : WCHAR *utf16;
1918 : : int dstlen;
1919 : : UINT codepage;
1920 : :
1921 : : if (msgenc == PG_SQL_ASCII)
1922 : : /* No conversion is possible, and SQL_ASCII is never utf16. */
1923 : : return NULL;
1924 : :
1925 : : codepage = pg_enc2name_tbl[msgenc].codepage;
1926 : :
1927 : : /*
1928 : : * Use MultiByteToWideChar directly if there is a corresponding codepage,
1929 : : * or double conversion through UTF8 if not. Double conversion is needed,
1930 : : * for example, in an ENCODING=LATIN8, LC_CTYPE=C database.
1931 : : */
1932 : : if (codepage != 0)
1933 : : {
1934 : : utf16 = palloc_array(WCHAR, len + 1);
1935 : : dstlen = MultiByteToWideChar(codepage, 0, str, len, utf16, len);
1936 : : utf16[dstlen] = (WCHAR) 0;
1937 : : }
1938 : : else
1939 : : {
1940 : : char *utf8;
1941 : :
1942 : : /*
1943 : : * XXX pg_do_encoding_conversion() requires a transaction. In the
1944 : : * absence of one, hope for the input to be valid UTF8.
1945 : : */
1946 : : if (IsTransactionState())
1947 : : {
1948 : : utf8 = (char *) pg_do_encoding_conversion((unsigned char *) str,
1949 : : len,
1950 : : msgenc,
1951 : : PG_UTF8);
1952 : : if (utf8 != str)
1953 : : len = strlen(utf8);
1954 : : }
1955 : : else
1956 : : utf8 = (char *) str;
1957 : :
1958 : : utf16 = palloc_array(WCHAR, len + 1);
1959 : : dstlen = MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, len);
1960 : : utf16[dstlen] = (WCHAR) 0;
1961 : :
1962 : : if (utf8 != str)
1963 : : pfree(utf8);
1964 : : }
1965 : :
1966 : : if (dstlen == 0 && len > 0)
1967 : : {
1968 : : pfree(utf16);
1969 : : return NULL; /* error */
1970 : : }
1971 : :
1972 : : if (utf16len)
1973 : : *utf16len = dstlen;
1974 : : return utf16;
1975 : : }
1976 : :
1977 : : #endif /* WIN32 */
|