Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * scansup.c
4 : : * scanner support routines used by the core lexer
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/parser/scansup.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include <ctype.h>
18 : :
19 : : #include "mb/pg_wchar.h"
20 : : #include "parser/scansup.h"
21 : :
22 : :
23 : : /*
24 : : * downcase_truncate_identifier() --- do appropriate downcasing and
25 : : * truncation of an unquoted identifier. Optionally warn of truncation.
26 : : *
27 : : * Returns a palloc'd string containing the adjusted identifier.
28 : : *
29 : : * Note: in some usages the passed string is not null-terminated.
30 : : *
31 : : * Note: the API of this function is designed to allow for downcasing
32 : : * transformations that increase the string length, but we don't yet
33 : : * support that. If you want to implement it, you'll need to fix
34 : : * SplitIdentifierString() in utils/adt/varlena.c.
35 : : */
36 : : char *
7358 tgl@sss.pgh.pa.us 37 :CBC 2714191 : downcase_truncate_identifier(const char *ident, int len, bool warn)
38 : : {
2949 teodor@sigaev.ru 39 : 2714191 : return downcase_identifier(ident, len, warn, true);
40 : : }
41 : :
42 : : /*
43 : : * a workhorse for downcase_truncate_identifier
44 : : */
45 : : char *
46 : 2714242 : downcase_identifier(const char *ident, int len, bool warn, bool truncate)
47 : : {
48 : : char *result;
49 : : int i;
50 : : bool enc_is_single_byte;
51 : :
7358 tgl@sss.pgh.pa.us 52 : 2714242 : result = palloc(len + 1);
3963 andrew@dunslane.net 53 : 2714242 : enc_is_single_byte = pg_database_encoding_max_length() == 1;
54 : :
55 : : /*
56 : : * SQL99 specifies Unicode-aware case normalization, which we don't yet
57 : : * have the infrastructure for. Instead we use tolower() to provide a
58 : : * locale-aware translation. However, there are some locales where this
59 : : * is not right either (eg, Turkish may do strange things with 'i' and
60 : : * 'I'). Our current compromise is to use tolower() for characters with
61 : : * the high bit set, as long as they aren't part of a multi-byte
62 : : * character, and use an ASCII-only downcasing for 7-bit characters.
63 : : */
7358 tgl@sss.pgh.pa.us 64 [ + + ]: 21478685 : for (i = 0; i < len; i++)
65 : : {
7168 bruce@momjian.us 66 : 18764443 : unsigned char ch = (unsigned char) ident[i];
67 : :
7358 tgl@sss.pgh.pa.us 68 [ + + + + ]: 18764443 : if (ch >= 'A' && ch <= 'Z')
69 : 485707 : ch += 'a' - 'A';
3963 andrew@dunslane.net 70 [ + + - + : 18278736 : else if (enc_is_single_byte && IS_HIGHBIT_SET(ch) && isupper(ch))
- - ]
7358 tgl@sss.pgh.pa.us 71 :UBC 0 : ch = tolower(ch);
7358 tgl@sss.pgh.pa.us 72 :CBC 18764443 : result[i] = (char) ch;
73 : : }
74 : 2714242 : result[i] = '\0';
75 : :
2949 teodor@sigaev.ru 76 [ + + + + ]: 2714242 : if (i >= NAMEDATALEN && truncate)
7358 tgl@sss.pgh.pa.us 77 : 6 : truncate_identifier(result, i, warn);
78 : :
79 : 2714242 : return result;
80 : : }
81 : :
82 : :
83 : : /*
84 : : * truncate_identifier() --- truncate an identifier to NAMEDATALEN-1 bytes.
85 : : *
86 : : * The given string is modified in-place, if necessary. A warning is
87 : : * issued if requested.
88 : : *
89 : : * We require the caller to pass in the string length since this saves a
90 : : * strlen() call in some common usages.
91 : : */
92 : : void
93 : 152873 : truncate_identifier(char *ident, int len, bool warn)
94 : : {
95 [ + + ]: 152873 : if (len >= NAMEDATALEN)
96 : : {
7168 bruce@momjian.us 97 : 17 : len = pg_mbcliplen(ident, len, NAMEDATALEN - 1);
7358 tgl@sss.pgh.pa.us 98 [ + + ]: 17 : if (warn)
99 [ + - ]: 7 : ereport(NOTICE,
100 : : (errcode(ERRCODE_NAME_TOO_LONG),
101 : : errmsg("identifier \"%s\" will be truncated to \"%.*s\"",
102 : : ident, len, ident)));
103 : 17 : ident[len] = '\0';
104 : : }
105 : 152873 : }
106 : :
107 : : /*
108 : : * scanner_isspace() --- return true if flex scanner considers char whitespace
109 : : *
110 : : * This should be used instead of the potentially locale-dependent isspace()
111 : : * function when it's important to match the lexer's behavior.
112 : : *
113 : : * In principle we might need similar functions for isalnum etc, but for the
114 : : * moment only isspace seems needed.
115 : : */
116 : : bool
6414 117 : 11038061 : scanner_isspace(char ch)
118 : : {
119 : : /* This must match scan.l's list of {space} characters */
120 [ + + + + ]: 11038061 : if (ch == ' ' ||
121 [ + + ]: 10989175 : ch == '\t' ||
122 [ + + ]: 10989045 : ch == '\n' ||
123 [ + + ]: 10989036 : ch == '\r' ||
283 michael@paquier.xyz 124 [ + + ]:GNC 10989033 : ch == '\v' ||
125 : : ch == '\f')
6414 tgl@sss.pgh.pa.us 126 :CBC 49031 : return true;
127 : 10989030 : return false;
128 : : }
|