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