Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * char.c
4 : : * Functions for the built-in type "char" (not to be confused with
5 : : * bpchar, which is the SQL CHAR(n) type).
6 : : *
7 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/backend/utils/adt/char.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : : #include "postgres.h"
17 : :
18 : : #include <limits.h>
19 : :
20 : : #include "libpq/pqformat.h"
21 : : #include "utils/fmgrprotos.h"
22 : : #include "varatt.h"
23 : :
24 : : #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
25 : : #define TOOCTAL(c) ((c) + '0')
26 : : #define FROMOCTAL(c) ((unsigned char) (c) - '0')
27 : :
28 : :
29 : : /*****************************************************************************
30 : : * USER I/O ROUTINES *
31 : : *****************************************************************************/
32 : :
33 : : /*
34 : : * charin - converts "x" to 'x'
35 : : *
36 : : * This accepts the formats charout produces. If we have multibyte input
37 : : * that is not in the form '\ooo', then we take its first byte as the value
38 : : * and silently discard the rest; this is a backwards-compatibility provision.
39 : : */
40 : : Datum
8714 tgl@sss.pgh.pa.us 41 :CBC 632676 : charin(PG_FUNCTION_ARGS)
42 : : {
43 : 632676 : char *ch = PG_GETARG_CSTRING(0);
44 : :
621 45 [ + + + - ]: 632676 : if (strlen(ch) == 4 && ch[0] == '\\' &&
46 [ + - + - : 12 : ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
+ - + - +
- + - ]
47 : 12 : PG_RETURN_CHAR((FROMOCTAL(ch[1]) << 6) +
48 : : (FROMOCTAL(ch[2]) << 3) +
49 : : FROMOCTAL(ch[3]));
50 : : /* This will do the right thing for a zero-length input string */
8714 51 : 632664 : PG_RETURN_CHAR(ch[0]);
52 : : }
53 : :
54 : : /*
55 : : * charout - converts 'x' to "x"
56 : : *
57 : : * The possible output formats are:
58 : : * 1. 0x00 is represented as an empty string.
59 : : * 2. 0x01..0x7F are represented as a single ASCII byte.
60 : : * 3. 0x80..0xFF are represented as \ooo (backslash and 3 octal digits).
61 : : * Case 3 is meant to match the traditional "escape" format of bytea.
62 : : */
63 : : Datum
64 : 1130803 : charout(PG_FUNCTION_ARGS)
65 : : {
66 : 1130803 : char ch = PG_GETARG_CHAR(0);
621 67 : 1130803 : char *result = (char *) palloc(5);
68 : :
69 [ + + ]: 1130803 : if (IS_HIGHBIT_SET(ch))
70 : : {
71 : 6 : result[0] = '\\';
72 : 6 : result[1] = TOOCTAL(((unsigned char) ch) >> 6);
73 : 6 : result[2] = TOOCTAL((((unsigned char) ch) >> 3) & 07);
74 : 6 : result[3] = TOOCTAL(((unsigned char) ch) & 07);
75 : 6 : result[4] = '\0';
76 : : }
77 : : else
78 : : {
79 : : /* This produces acceptable results for 0x00 as well */
80 : 1130797 : result[0] = ch;
81 : 1130797 : result[1] = '\0';
82 : : }
8714 83 : 1130803 : PG_RETURN_CSTRING(result);
84 : : }
85 : :
86 : : /*
87 : : * charrecv - converts external binary format to char
88 : : *
89 : : * The external representation is one byte, with no character set
90 : : * conversion. This is somewhat dubious, perhaps, but in many
91 : : * cases people use char for a 1-byte binary type.
92 : : */
93 : : Datum
7643 tgl@sss.pgh.pa.us 94 :UBC 0 : charrecv(PG_FUNCTION_ARGS)
95 : : {
96 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
97 : :
98 : 0 : PG_RETURN_CHAR(pq_getmsgbyte(buf));
99 : : }
100 : :
101 : : /*
102 : : * charsend - converts char to binary format
103 : : */
104 : : Datum
105 : 0 : charsend(PG_FUNCTION_ARGS)
106 : : {
107 : 0 : char arg1 = PG_GETARG_CHAR(0);
108 : : StringInfoData buf;
109 : :
110 : 0 : pq_begintypsend(&buf);
111 : 0 : pq_sendbyte(&buf, arg1);
112 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
113 : : }
114 : :
115 : : /*****************************************************************************
116 : : * PUBLIC ROUTINES *
117 : : *****************************************************************************/
118 : :
119 : : /*
120 : : * NOTE: comparisons are done as though char is unsigned (uint8).
121 : : * Conversions to and from integer are done as though char is signed (int8).
122 : : *
123 : : * You wanted consistency?
124 : : */
125 : :
126 : : Datum
8714 tgl@sss.pgh.pa.us 127 :CBC 3075641 : chareq(PG_FUNCTION_ARGS)
128 : : {
129 : 3075641 : char arg1 = PG_GETARG_CHAR(0);
130 : 3075641 : char arg2 = PG_GETARG_CHAR(1);
131 : :
132 : 3075641 : PG_RETURN_BOOL(arg1 == arg2);
133 : : }
134 : :
135 : : Datum
136 : 1736705 : charne(PG_FUNCTION_ARGS)
137 : : {
138 : 1736705 : char arg1 = PG_GETARG_CHAR(0);
139 : 1736705 : char arg2 = PG_GETARG_CHAR(1);
140 : :
141 : 1736705 : PG_RETURN_BOOL(arg1 != arg2);
142 : : }
143 : :
144 : : Datum
145 : 1548 : charlt(PG_FUNCTION_ARGS)
146 : : {
147 : 1548 : char arg1 = PG_GETARG_CHAR(0);
148 : 1548 : char arg2 = PG_GETARG_CHAR(1);
149 : :
150 : 1548 : PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
151 : : }
152 : :
153 : : Datum
154 : 1212 : charle(PG_FUNCTION_ARGS)
155 : : {
156 : 1212 : char arg1 = PG_GETARG_CHAR(0);
157 : 1212 : char arg2 = PG_GETARG_CHAR(1);
158 : :
159 : 1212 : PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
160 : : }
161 : :
162 : : Datum
163 : 1521 : chargt(PG_FUNCTION_ARGS)
164 : : {
165 : 1521 : char arg1 = PG_GETARG_CHAR(0);
166 : 1521 : char arg2 = PG_GETARG_CHAR(1);
167 : :
168 : 1521 : PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
169 : : }
170 : :
171 : : Datum
172 : 1065 : charge(PG_FUNCTION_ARGS)
173 : : {
174 : 1065 : char arg1 = PG_GETARG_CHAR(0);
175 : 1065 : char arg2 = PG_GETARG_CHAR(1);
176 : :
177 : 1065 : PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
178 : : }
179 : :
180 : :
181 : : Datum
7132 tgl@sss.pgh.pa.us 182 :UBC 0 : chartoi4(PG_FUNCTION_ARGS)
183 : : {
8714 184 : 0 : char arg1 = PG_GETARG_CHAR(0);
185 : :
7132 186 : 0 : PG_RETURN_INT32((int32) ((int8) arg1));
187 : : }
188 : :
189 : : Datum
190 : 0 : i4tochar(PG_FUNCTION_ARGS)
191 : : {
192 : 0 : int32 arg1 = PG_GETARG_INT32(0);
193 : :
194 [ # # # # ]: 0 : if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
7567 195 [ # # ]: 0 : ereport(ERROR,
196 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
197 : : errmsg("\"char\" out of range")));
198 : :
7132 199 : 0 : PG_RETURN_CHAR((int8) arg1);
200 : : }
201 : :
202 : :
203 : : Datum
8714 tgl@sss.pgh.pa.us 204 :CBC 5407 : text_char(PG_FUNCTION_ARGS)
205 : : {
2590 noah@leadboat.com 206 : 5407 : text *arg1 = PG_GETARG_TEXT_PP(0);
621 tgl@sss.pgh.pa.us 207 [ - + ]: 5407 : char *ch = VARDATA_ANY(arg1);
208 : : char result;
209 : :
210 : : /*
211 : : * Conversion rules are the same as in charin(), but here we need to
212 : : * handle the empty-string case honestly.
213 : : */
214 [ - + - - : 5407 : if (VARSIZE_ANY_EXHDR(arg1) == 4 && ch[0] == '\\' &&
- - - - -
+ - - + +
+ - ]
215 [ + - + - : 3 : ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
+ - + - +
- + - ]
216 : 3 : result = (FROMOCTAL(ch[1]) << 6) +
217 : 3 : (FROMOCTAL(ch[2]) << 3) +
218 : 3 : FROMOCTAL(ch[3]);
219 [ - + - - : 5404 : else if (VARSIZE_ANY_EXHDR(arg1) > 0)
- - - - -
+ + + ]
220 : 5401 : result = ch[0];
221 : : else
8357 222 : 3 : result = '\0';
223 : :
224 : 5407 : PG_RETURN_CHAR(result);
225 : : }
226 : :
227 : : Datum
8714 228 : 24139 : char_text(PG_FUNCTION_ARGS)
229 : : {
230 : 24139 : char arg1 = PG_GETARG_CHAR(0);
621 231 : 24139 : text *result = palloc(VARHDRSZ + 4);
232 : :
233 : : /*
234 : : * Conversion rules are the same as in charout(), but here we need to be
235 : : * honest about converting 0x00 to an empty string.
236 : : */
237 [ + + ]: 24139 : if (IS_HIGHBIT_SET(arg1))
238 : : {
239 : 3 : SET_VARSIZE(result, VARHDRSZ + 4);
240 : 3 : (VARDATA(result))[0] = '\\';
241 : 3 : (VARDATA(result))[1] = TOOCTAL(((unsigned char) arg1) >> 6);
242 : 3 : (VARDATA(result))[2] = TOOCTAL((((unsigned char) arg1) >> 3) & 07);
243 : 3 : (VARDATA(result))[3] = TOOCTAL(((unsigned char) arg1) & 07);
244 : : }
245 [ + + ]: 24136 : else if (arg1 != '\0')
246 : : {
6256 247 : 24133 : SET_VARSIZE(result, VARHDRSZ + 1);
8357 248 : 24133 : *(VARDATA(result)) = arg1;
249 : : }
250 : : else
6256 251 : 3 : SET_VARSIZE(result, VARHDRSZ);
252 : :
8714 253 : 24139 : PG_RETURN_TEXT_P(result);
254 : : }
|