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-2019, 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/builtins.h" |
22 | |
23 | /***************************************************************************** |
24 | * USER I/O ROUTINES * |
25 | *****************************************************************************/ |
26 | |
27 | /* |
28 | * charin - converts "x" to 'x' |
29 | * |
30 | * Note that an empty input string will implicitly be converted to \0. |
31 | */ |
32 | Datum |
33 | charin(PG_FUNCTION_ARGS) |
34 | { |
35 | char *ch = PG_GETARG_CSTRING(0); |
36 | |
37 | PG_RETURN_CHAR(ch[0]); |
38 | } |
39 | |
40 | /* |
41 | * charout - converts 'x' to "x" |
42 | * |
43 | * Note that if the char value is \0, the resulting string will appear |
44 | * to be empty (null-terminated after zero characters). So this is the |
45 | * inverse of the charin() function for such data. |
46 | */ |
47 | Datum |
48 | charout(PG_FUNCTION_ARGS) |
49 | { |
50 | char ch = PG_GETARG_CHAR(0); |
51 | char *result = (char *) palloc(2); |
52 | |
53 | result[0] = ch; |
54 | result[1] = '\0'; |
55 | PG_RETURN_CSTRING(result); |
56 | } |
57 | |
58 | /* |
59 | * charrecv - converts external binary format to char |
60 | * |
61 | * The external representation is one byte, with no character set |
62 | * conversion. This is somewhat dubious, perhaps, but in many |
63 | * cases people use char for a 1-byte binary type. |
64 | */ |
65 | Datum |
66 | charrecv(PG_FUNCTION_ARGS) |
67 | { |
68 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
69 | |
70 | PG_RETURN_CHAR(pq_getmsgbyte(buf)); |
71 | } |
72 | |
73 | /* |
74 | * charsend - converts char to binary format |
75 | */ |
76 | Datum |
77 | charsend(PG_FUNCTION_ARGS) |
78 | { |
79 | char arg1 = PG_GETARG_CHAR(0); |
80 | StringInfoData buf; |
81 | |
82 | pq_begintypsend(&buf); |
83 | pq_sendbyte(&buf, arg1); |
84 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
85 | } |
86 | |
87 | /***************************************************************************** |
88 | * PUBLIC ROUTINES * |
89 | *****************************************************************************/ |
90 | |
91 | /* |
92 | * NOTE: comparisons are done as though char is unsigned (uint8). |
93 | * Conversions to and from integer are done as though char is signed (int8). |
94 | * |
95 | * You wanted consistency? |
96 | */ |
97 | |
98 | Datum |
99 | chareq(PG_FUNCTION_ARGS) |
100 | { |
101 | char arg1 = PG_GETARG_CHAR(0); |
102 | char arg2 = PG_GETARG_CHAR(1); |
103 | |
104 | PG_RETURN_BOOL(arg1 == arg2); |
105 | } |
106 | |
107 | Datum |
108 | charne(PG_FUNCTION_ARGS) |
109 | { |
110 | char arg1 = PG_GETARG_CHAR(0); |
111 | char arg2 = PG_GETARG_CHAR(1); |
112 | |
113 | PG_RETURN_BOOL(arg1 != arg2); |
114 | } |
115 | |
116 | Datum |
117 | charlt(PG_FUNCTION_ARGS) |
118 | { |
119 | char arg1 = PG_GETARG_CHAR(0); |
120 | char arg2 = PG_GETARG_CHAR(1); |
121 | |
122 | PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2); |
123 | } |
124 | |
125 | Datum |
126 | charle(PG_FUNCTION_ARGS) |
127 | { |
128 | char arg1 = PG_GETARG_CHAR(0); |
129 | char arg2 = PG_GETARG_CHAR(1); |
130 | |
131 | PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2); |
132 | } |
133 | |
134 | Datum |
135 | chargt(PG_FUNCTION_ARGS) |
136 | { |
137 | char arg1 = PG_GETARG_CHAR(0); |
138 | char arg2 = PG_GETARG_CHAR(1); |
139 | |
140 | PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2); |
141 | } |
142 | |
143 | Datum |
144 | charge(PG_FUNCTION_ARGS) |
145 | { |
146 | char arg1 = PG_GETARG_CHAR(0); |
147 | char arg2 = PG_GETARG_CHAR(1); |
148 | |
149 | PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2); |
150 | } |
151 | |
152 | |
153 | Datum |
154 | chartoi4(PG_FUNCTION_ARGS) |
155 | { |
156 | char arg1 = PG_GETARG_CHAR(0); |
157 | |
158 | PG_RETURN_INT32((int32) ((int8) arg1)); |
159 | } |
160 | |
161 | Datum |
162 | i4tochar(PG_FUNCTION_ARGS) |
163 | { |
164 | int32 arg1 = PG_GETARG_INT32(0); |
165 | |
166 | if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX) |
167 | ereport(ERROR, |
168 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
169 | errmsg("\"char\" out of range" ))); |
170 | |
171 | PG_RETURN_CHAR((int8) arg1); |
172 | } |
173 | |
174 | |
175 | Datum |
176 | text_char(PG_FUNCTION_ARGS) |
177 | { |
178 | text *arg1 = PG_GETARG_TEXT_PP(0); |
179 | char result; |
180 | |
181 | /* |
182 | * An empty input string is converted to \0 (for consistency with charin). |
183 | * If the input is longer than one character, the excess data is silently |
184 | * discarded. |
185 | */ |
186 | if (VARSIZE_ANY_EXHDR(arg1) > 0) |
187 | result = *(VARDATA_ANY(arg1)); |
188 | else |
189 | result = '\0'; |
190 | |
191 | PG_RETURN_CHAR(result); |
192 | } |
193 | |
194 | Datum |
195 | char_text(PG_FUNCTION_ARGS) |
196 | { |
197 | char arg1 = PG_GETARG_CHAR(0); |
198 | text *result = palloc(VARHDRSZ + 1); |
199 | |
200 | /* |
201 | * Convert \0 to an empty string, for consistency with charout (and |
202 | * because the text stuff doesn't like embedded nulls all that well). |
203 | */ |
204 | if (arg1 != '\0') |
205 | { |
206 | SET_VARSIZE(result, VARHDRSZ + 1); |
207 | *(VARDATA(result)) = arg1; |
208 | } |
209 | else |
210 | SET_VARSIZE(result, VARHDRSZ); |
211 | |
212 | PG_RETURN_TEXT_P(result); |
213 | } |
214 | |