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