Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * bool.c
4 : * Functions for the built-in type "bool".
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/bool.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include <ctype.h>
19 :
20 : #include "libpq/pqformat.h"
21 : #include "utils/builtins.h"
22 :
23 : /*
24 : * Try to interpret value as boolean value. Valid values are: true,
25 : * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof.
26 : * If the string parses okay, return true, else false.
27 : * If okay and result is not NULL, return the value in *result.
28 : */
29 : bool
30 125780 : parse_bool(const char *value, bool *result)
31 : {
32 125780 : return parse_bool_with_len(value, strlen(value), result);
33 : }
34 :
35 : bool
36 2620738 : parse_bool_with_len(const char *value, size_t len, bool *result)
37 : {
38 : /* Check the most-used possibilities first. */
39 2620738 : switch (*value)
40 : {
41 294538 : case 't':
42 : case 'T':
43 294538 : if (pg_strncasecmp(value, "true", len) == 0)
44 : {
45 294526 : if (result)
46 294526 : *result = true;
47 294526 : return true;
48 : }
49 12 : break;
50 2234186 : case 'f':
51 : case 'F':
52 2234186 : if (pg_strncasecmp(value, "false", len) == 0)
53 : {
54 2234174 : if (result)
55 2234174 : *result = false;
56 2234174 : return true;
57 : }
58 12 : break;
59 398 : case 'y':
60 : case 'Y':
61 398 : if (pg_strncasecmp(value, "yes", len) == 0)
62 : {
63 392 : if (result)
64 392 : *result = true;
65 392 : return true;
66 : }
67 6 : break;
68 4682 : case 'n':
69 : case 'N':
70 4682 : if (pg_strncasecmp(value, "no", len) == 0)
71 : {
72 4676 : if (result)
73 4676 : *result = false;
74 4676 : return true;
75 : }
76 6 : break;
77 74252 : case 'o':
78 : case 'O':
79 : /* 'o' is not unique enough */
80 74252 : if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
81 : {
82 58166 : if (result)
83 58166 : *result = true;
84 58166 : return true;
85 : }
86 16086 : else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
87 : {
88 16068 : if (result)
89 16068 : *result = false;
90 16068 : return true;
91 : }
92 18 : break;
93 6902 : case '1':
94 6902 : if (len == 1)
95 : {
96 6878 : if (result)
97 6878 : *result = true;
98 6878 : return true;
99 : }
100 24 : break;
101 5732 : case '0':
102 5732 : if (len == 1)
103 : {
104 5726 : if (result)
105 5726 : *result = false;
106 5726 : return true;
107 : }
108 6 : break;
109 48 : default:
110 48 : break;
111 : }
112 :
113 132 : if (result)
114 132 : *result = false; /* suppress compiler warning */
115 132 : return false;
116 : }
117 :
118 : /*****************************************************************************
119 : * USER I/O ROUTINES *
120 : *****************************************************************************/
121 :
122 : /*
123 : * boolin - input function for type boolean
124 : */
125 : Datum
126 2494958 : boolin(PG_FUNCTION_ARGS)
127 : {
128 2494958 : const char *in_str = PG_GETARG_CSTRING(0);
129 : const char *str;
130 : size_t len;
131 : bool result;
132 :
133 : /*
134 : * Skip leading and trailing whitespace
135 : */
136 2494958 : str = in_str;
137 2495042 : while (isspace((unsigned char) *str))
138 84 : str++;
139 :
140 2494958 : len = strlen(str);
141 2495048 : while (len > 0 && isspace((unsigned char) str[len - 1]))
142 90 : len--;
143 :
144 2494958 : if (parse_bool_with_len(str, len, &result))
145 2494868 : PG_RETURN_BOOL(result);
146 :
147 90 : ereturn(fcinfo->context, (Datum) 0,
148 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
149 : errmsg("invalid input syntax for type %s: \"%s\"",
150 : "boolean", in_str)));
151 : }
152 :
153 : /*
154 : * boolout - converts 1 or 0 to "t" or "f"
155 : */
156 : Datum
157 1841440 : boolout(PG_FUNCTION_ARGS)
158 : {
159 1841440 : bool b = PG_GETARG_BOOL(0);
160 1841440 : char *result = (char *) palloc(2);
161 :
162 1841440 : result[0] = (b) ? 't' : 'f';
163 1841440 : result[1] = '\0';
164 1841440 : PG_RETURN_CSTRING(result);
165 : }
166 :
167 : /*
168 : * boolrecv - converts external binary format to bool
169 : *
170 : * The external representation is one byte. Any nonzero value is taken
171 : * as "true".
172 : */
173 : Datum
174 0 : boolrecv(PG_FUNCTION_ARGS)
175 : {
176 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
177 : int ext;
178 :
179 0 : ext = pq_getmsgbyte(buf);
180 0 : PG_RETURN_BOOL(ext != 0);
181 : }
182 :
183 : /*
184 : * boolsend - converts bool to binary format
185 : */
186 : Datum
187 0 : boolsend(PG_FUNCTION_ARGS)
188 : {
189 0 : bool arg1 = PG_GETARG_BOOL(0);
190 : StringInfoData buf;
191 :
192 0 : pq_begintypsend(&buf);
193 0 : pq_sendbyte(&buf, arg1 ? 1 : 0);
194 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
195 : }
196 :
197 : /*
198 : * booltext - cast function for bool => text
199 : *
200 : * We need this because it's different from the behavior of boolout();
201 : * this function follows the SQL-spec result (except for producing lower case)
202 : */
203 : Datum
204 132 : booltext(PG_FUNCTION_ARGS)
205 : {
206 132 : bool arg1 = PG_GETARG_BOOL(0);
207 : const char *str;
208 :
209 132 : if (arg1)
210 60 : str = "true";
211 : else
212 72 : str = "false";
213 :
214 132 : PG_RETURN_TEXT_P(cstring_to_text(str));
215 : }
216 :
217 :
218 : /*****************************************************************************
219 : * PUBLIC ROUTINES *
220 : *****************************************************************************/
221 :
222 : Datum
223 281102 : booleq(PG_FUNCTION_ARGS)
224 : {
225 281102 : bool arg1 = PG_GETARG_BOOL(0);
226 281102 : bool arg2 = PG_GETARG_BOOL(1);
227 :
228 281102 : PG_RETURN_BOOL(arg1 == arg2);
229 : }
230 :
231 : Datum
232 75630 : boolne(PG_FUNCTION_ARGS)
233 : {
234 75630 : bool arg1 = PG_GETARG_BOOL(0);
235 75630 : bool arg2 = PG_GETARG_BOOL(1);
236 :
237 75630 : PG_RETURN_BOOL(arg1 != arg2);
238 : }
239 :
240 : Datum
241 10 : boollt(PG_FUNCTION_ARGS)
242 : {
243 10 : bool arg1 = PG_GETARG_BOOL(0);
244 10 : bool arg2 = PG_GETARG_BOOL(1);
245 :
246 10 : PG_RETURN_BOOL(arg1 < arg2);
247 : }
248 :
249 : Datum
250 10 : boolgt(PG_FUNCTION_ARGS)
251 : {
252 10 : bool arg1 = PG_GETARG_BOOL(0);
253 10 : bool arg2 = PG_GETARG_BOOL(1);
254 :
255 10 : PG_RETURN_BOOL(arg1 > arg2);
256 : }
257 :
258 : Datum
259 16 : boolle(PG_FUNCTION_ARGS)
260 : {
261 16 : bool arg1 = PG_GETARG_BOOL(0);
262 16 : bool arg2 = PG_GETARG_BOOL(1);
263 :
264 16 : PG_RETURN_BOOL(arg1 <= arg2);
265 : }
266 :
267 : Datum
268 16 : boolge(PG_FUNCTION_ARGS)
269 : {
270 16 : bool arg1 = PG_GETARG_BOOL(0);
271 16 : bool arg2 = PG_GETARG_BOOL(1);
272 :
273 16 : PG_RETURN_BOOL(arg1 >= arg2);
274 : }
275 :
276 : /*
277 : * boolean-and and boolean-or aggregates.
278 : */
279 :
280 : /*
281 : * Function for standard EVERY aggregate conforming to SQL 2003.
282 : * The aggregate is also named bool_and for consistency.
283 : *
284 : * Note: this is only used in plain aggregate mode, not moving-aggregate mode.
285 : */
286 : Datum
287 132 : booland_statefunc(PG_FUNCTION_ARGS)
288 : {
289 132 : PG_RETURN_BOOL(PG_GETARG_BOOL(0) && PG_GETARG_BOOL(1));
290 : }
291 :
292 : /*
293 : * Function for standard ANY/SOME aggregate conforming to SQL 2003.
294 : * The aggregate is named bool_or, because ANY/SOME have parsing conflicts.
295 : *
296 : * Note: this is only used in plain aggregate mode, not moving-aggregate mode.
297 : */
298 : Datum
299 56 : boolor_statefunc(PG_FUNCTION_ARGS)
300 : {
301 56 : PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1));
302 : }
303 :
304 : typedef struct BoolAggState
305 : {
306 : int64 aggcount; /* number of non-null values aggregated */
307 : int64 aggtrue; /* number of values aggregated that are true */
308 : } BoolAggState;
309 :
310 : static BoolAggState *
311 12 : makeBoolAggState(FunctionCallInfo fcinfo)
312 : {
313 : BoolAggState *state;
314 : MemoryContext agg_context;
315 :
316 12 : if (!AggCheckCallContext(fcinfo, &agg_context))
317 0 : elog(ERROR, "aggregate function called in non-aggregate context");
318 :
319 12 : state = (BoolAggState *) MemoryContextAlloc(agg_context,
320 : sizeof(BoolAggState));
321 12 : state->aggcount = 0;
322 12 : state->aggtrue = 0;
323 :
324 12 : return state;
325 : }
326 :
327 : Datum
328 60 : bool_accum(PG_FUNCTION_ARGS)
329 : {
330 : BoolAggState *state;
331 :
332 60 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
333 :
334 : /* Create the state data on first call */
335 60 : if (state == NULL)
336 12 : state = makeBoolAggState(fcinfo);
337 :
338 60 : if (!PG_ARGISNULL(1))
339 : {
340 60 : state->aggcount++;
341 60 : if (PG_GETARG_BOOL(1))
342 36 : state->aggtrue++;
343 : }
344 :
345 60 : PG_RETURN_POINTER(state);
346 : }
347 :
348 : Datum
349 48 : bool_accum_inv(PG_FUNCTION_ARGS)
350 : {
351 : BoolAggState *state;
352 :
353 48 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
354 :
355 : /* bool_accum should have created the state data */
356 48 : if (state == NULL)
357 0 : elog(ERROR, "bool_accum_inv called with NULL state");
358 :
359 48 : if (!PG_ARGISNULL(1))
360 : {
361 48 : state->aggcount--;
362 48 : if (PG_GETARG_BOOL(1))
363 24 : state->aggtrue--;
364 : }
365 :
366 48 : PG_RETURN_POINTER(state);
367 : }
368 :
369 : Datum
370 30 : bool_alltrue(PG_FUNCTION_ARGS)
371 : {
372 : BoolAggState *state;
373 :
374 30 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
375 :
376 : /* if there were no non-null values, return NULL */
377 30 : if (state == NULL || state->aggcount == 0)
378 0 : PG_RETURN_NULL();
379 :
380 : /* true if all non-null values are true */
381 30 : PG_RETURN_BOOL(state->aggtrue == state->aggcount);
382 : }
383 :
384 : Datum
385 30 : bool_anytrue(PG_FUNCTION_ARGS)
386 : {
387 : BoolAggState *state;
388 :
389 30 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
390 :
391 : /* if there were no non-null values, return NULL */
392 30 : if (state == NULL || state->aggcount == 0)
393 0 : PG_RETURN_NULL();
394 :
395 : /* true if any non-null value is true */
396 30 : PG_RETURN_BOOL(state->aggtrue > 0);
397 : }
|