PostgreSQL Source Code  git master
char.c
Go to the documentation of this file.
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
42 {
43  char *ch = PG_GETARG_CSTRING(0);
44 
45  if (strlen(ch) == 4 && ch[0] == '\\' &&
46  ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
47  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 */
51  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
65 {
66  char ch = PG_GETARG_CHAR(0);
67  char *result = (char *) palloc(5);
68 
69  if (IS_HIGHBIT_SET(ch))
70  {
71  result[0] = '\\';
72  result[1] = TOOCTAL(((unsigned char) ch) >> 6);
73  result[2] = TOOCTAL((((unsigned char) ch) >> 3) & 07);
74  result[3] = TOOCTAL(((unsigned char) ch) & 07);
75  result[4] = '\0';
76  }
77  else
78  {
79  /* This produces acceptable results for 0x00 as well */
80  result[0] = ch;
81  result[1] = '\0';
82  }
83  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
95 {
97 
99 }
100 
101 /*
102  * charsend - converts char to binary format
103  */
104 Datum
106 {
107  char arg1 = PG_GETARG_CHAR(0);
109 
111  pq_sendbyte(&buf, arg1);
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
128 {
129  char arg1 = PG_GETARG_CHAR(0);
130  char arg2 = PG_GETARG_CHAR(1);
131 
132  PG_RETURN_BOOL(arg1 == arg2);
133 }
134 
135 Datum
137 {
138  char arg1 = PG_GETARG_CHAR(0);
139  char arg2 = PG_GETARG_CHAR(1);
140 
141  PG_RETURN_BOOL(arg1 != arg2);
142 }
143 
144 Datum
146 {
147  char arg1 = PG_GETARG_CHAR(0);
148  char arg2 = PG_GETARG_CHAR(1);
149 
150  PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
151 }
152 
153 Datum
155 {
156  char arg1 = PG_GETARG_CHAR(0);
157  char arg2 = PG_GETARG_CHAR(1);
158 
159  PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
160 }
161 
162 Datum
164 {
165  char arg1 = PG_GETARG_CHAR(0);
166  char arg2 = PG_GETARG_CHAR(1);
167 
168  PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
169 }
170 
171 Datum
173 {
174  char arg1 = PG_GETARG_CHAR(0);
175  char arg2 = PG_GETARG_CHAR(1);
176 
177  PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
178 }
179 
180 
181 Datum
183 {
184  char arg1 = PG_GETARG_CHAR(0);
185 
186  PG_RETURN_INT32((int32) ((int8) arg1));
187 }
188 
189 Datum
191 {
192  int32 arg1 = PG_GETARG_INT32(0);
193 
194  if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
195  ereport(ERROR,
196  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
197  errmsg("\"char\" out of range")));
198 
199  PG_RETURN_CHAR((int8) arg1);
200 }
201 
202 
203 Datum
205 {
206  text *arg1 = PG_GETARG_TEXT_PP(0);
207  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  if (VARSIZE_ANY_EXHDR(arg1) == 4 && ch[0] == '\\' &&
215  ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
216  result = (FROMOCTAL(ch[1]) << 6) +
217  (FROMOCTAL(ch[2]) << 3) +
218  FROMOCTAL(ch[3]);
219  else if (VARSIZE_ANY_EXHDR(arg1) > 0)
220  result = ch[0];
221  else
222  result = '\0';
223 
224  PG_RETURN_CHAR(result);
225 }
226 
227 Datum
229 {
230  char arg1 = PG_GETARG_CHAR(0);
231  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  if (IS_HIGHBIT_SET(arg1))
238  {
239  SET_VARSIZE(result, VARHDRSZ + 4);
240  (VARDATA(result))[0] = '\\';
241  (VARDATA(result))[1] = TOOCTAL(((unsigned char) arg1) >> 6);
242  (VARDATA(result))[2] = TOOCTAL((((unsigned char) arg1) >> 3) & 07);
243  (VARDATA(result))[3] = TOOCTAL(((unsigned char) arg1) & 07);
244  }
245  else if (arg1 != '\0')
246  {
247  SET_VARSIZE(result, VARHDRSZ + 1);
248  *(VARDATA(result)) = arg1;
249  }
250  else
251  SET_VARSIZE(result, VARHDRSZ);
252 
253  PG_RETURN_TEXT_P(result);
254 }
signed char int8
Definition: c.h:495
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1158
signed int int32
Definition: c.h:497
#define VARHDRSZ
Definition: c.h:695
unsigned char uint8
Definition: c.h:507
Datum charge(PG_FUNCTION_ARGS)
Definition: char.c:172
Datum charle(PG_FUNCTION_ARGS)
Definition: char.c:154
Datum chareq(PG_FUNCTION_ARGS)
Definition: char.c:127
Datum charrecv(PG_FUNCTION_ARGS)
Definition: char.c:94
Datum chargt(PG_FUNCTION_ARGS)
Definition: char.c:163
Datum chartoi4(PG_FUNCTION_ARGS)
Definition: char.c:182
#define ISOCTAL(c)
Definition: char.c:24
Datum text_char(PG_FUNCTION_ARGS)
Definition: char.c:204
Datum charne(PG_FUNCTION_ARGS)
Definition: char.c:136
Datum charin(PG_FUNCTION_ARGS)
Definition: char.c:41
Datum charsend(PG_FUNCTION_ARGS)
Definition: char.c:105
#define FROMOCTAL(c)
Definition: char.c:26
#define TOOCTAL(c)
Definition: char.c:25
Datum charlt(PG_FUNCTION_ARGS)
Definition: char.c:145
Datum charout(PG_FUNCTION_ARGS)
Definition: char.c:64
Datum char_text(PG_FUNCTION_ARGS)
Definition: char.c:228
Datum i4tochar(PG_FUNCTION_ARGS)
Definition: char.c:190
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:273
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_CHAR(x)
Definition: fmgr.h:358
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
void * palloc(Size size)
Definition: mcxt.c:1317
static char * buf
Definition: pg_test_fsync.c:73
uintptr_t Datum
Definition: postgres.h:64
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:399
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendbyte(StringInfo buf, uint8 byt)
Definition: pqformat.h:160
StringInfoData * StringInfo
Definition: stringinfo.h:54
Definition: c.h:690
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317