Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * bool.c
4 : * Functions for the built-in type "bool".
5 : *
6 : * Portions Copyright (c) 1996-2024, 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 157422 : parse_bool(const char *value, bool *result)
32 : {
33 157422 : return parse_bool_with_len(value, strlen(value), result);
34 : }
35 :
36 : bool
37 3043530 : parse_bool_with_len(const char *value, size_t len, bool *result)
38 : {
39 : /* Check the most-used possibilities first. */
40 3043530 : switch (*value)
41 : {
42 417094 : case 't':
43 : case 'T':
44 417094 : if (pg_strncasecmp(value, "true", len) == 0)
45 : {
46 417082 : if (result)
47 417082 : *result = true;
48 417082 : return true;
49 : }
50 12 : break;
51 2508274 : case 'f':
52 : case 'F':
53 2508274 : if (pg_strncasecmp(value, "false", len) == 0)
54 : {
55 2508256 : if (result)
56 2508256 : *result = false;
57 2508256 : return true;
58 : }
59 18 : break;
60 2168 : case 'y':
61 : case 'Y':
62 2168 : if (pg_strncasecmp(value, "yes", len) == 0)
63 : {
64 2162 : if (result)
65 2162 : *result = true;
66 2162 : return true;
67 : }
68 6 : break;
69 4010 : case 'n':
70 : case 'N':
71 4010 : if (pg_strncasecmp(value, "no", len) == 0)
72 : {
73 3992 : if (result)
74 3992 : *result = false;
75 3992 : return true;
76 : }
77 18 : break;
78 99046 : case 'o':
79 : case 'O':
80 : /* 'o' is not unique enough */
81 99046 : if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
82 : {
83 75182 : if (result)
84 75182 : *result = true;
85 75182 : return true;
86 : }
87 23864 : else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
88 : {
89 23846 : if (result)
90 23846 : *result = false;
91 23846 : return true;
92 : }
93 18 : break;
94 7022 : case '1':
95 7022 : if (len == 1)
96 : {
97 6974 : if (result)
98 6974 : *result = true;
99 6974 : return true;
100 : }
101 48 : break;
102 5814 : case '0':
103 5814 : if (len == 1)
104 : {
105 5808 : if (result)
106 5808 : *result = false;
107 5808 : return true;
108 : }
109 6 : break;
110 102 : default:
111 102 : break;
112 : }
113 :
114 228 : if (result)
115 228 : *result = false; /* suppress compiler warning */
116 228 : return false;
117 : }
118 :
119 : /*****************************************************************************
120 : * USER I/O ROUTINES *
121 : *****************************************************************************/
122 :
123 : /*
124 : * boolin - input function for type boolean
125 : */
126 : Datum
127 2886108 : boolin(PG_FUNCTION_ARGS)
128 : {
129 2886108 : const char *in_str = PG_GETARG_CSTRING(0);
130 : const char *str;
131 : size_t len;
132 : bool result;
133 :
134 : /*
135 : * Skip leading and trailing whitespace
136 : */
137 2886108 : str = in_str;
138 2886192 : while (isspace((unsigned char) *str))
139 84 : str++;
140 :
141 2886108 : len = strlen(str);
142 2886198 : while (len > 0 && isspace((unsigned char) str[len - 1]))
143 90 : len--;
144 :
145 2886108 : if (parse_bool_with_len(str, len, &result))
146 2885976 : PG_RETURN_BOOL(result);
147 :
148 132 : 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 : }
153 :
154 : /*
155 : * boolout - converts 1 or 0 to "t" or "f"
156 : */
157 : Datum
158 2528828 : boolout(PG_FUNCTION_ARGS)
159 : {
160 2528828 : bool b = PG_GETARG_BOOL(0);
161 2528828 : char *result = (char *) palloc(2);
162 :
163 2528828 : result[0] = (b) ? 't' : 'f';
164 2528828 : result[1] = '\0';
165 2528828 : PG_RETURN_CSTRING(result);
166 : }
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 : int ext;
179 :
180 0 : ext = pq_getmsgbyte(buf);
181 0 : PG_RETURN_BOOL(ext != 0);
182 : }
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 : 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 : }
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 144 : booltext(PG_FUNCTION_ARGS)
206 : {
207 144 : bool arg1 = PG_GETARG_BOOL(0);
208 : const char *str;
209 :
210 144 : if (arg1)
211 66 : str = "true";
212 : else
213 78 : str = "false";
214 :
215 144 : PG_RETURN_TEXT_P(cstring_to_text(str));
216 : }
217 :
218 :
219 : /*****************************************************************************
220 : * PUBLIC ROUTINES *
221 : *****************************************************************************/
222 :
223 : Datum
224 304474 : booleq(PG_FUNCTION_ARGS)
225 : {
226 304474 : bool arg1 = PG_GETARG_BOOL(0);
227 304474 : bool arg2 = PG_GETARG_BOOL(1);
228 :
229 304474 : PG_RETURN_BOOL(arg1 == arg2);
230 : }
231 :
232 : Datum
233 76436 : boolne(PG_FUNCTION_ARGS)
234 : {
235 76436 : bool arg1 = PG_GETARG_BOOL(0);
236 76436 : bool arg2 = PG_GETARG_BOOL(1);
237 :
238 76436 : PG_RETURN_BOOL(arg1 != arg2);
239 : }
240 :
241 : Datum
242 10 : boollt(PG_FUNCTION_ARGS)
243 : {
244 10 : bool arg1 = PG_GETARG_BOOL(0);
245 10 : bool arg2 = PG_GETARG_BOOL(1);
246 :
247 10 : PG_RETURN_BOOL(arg1 < arg2);
248 : }
249 :
250 : Datum
251 10 : boolgt(PG_FUNCTION_ARGS)
252 : {
253 10 : bool arg1 = PG_GETARG_BOOL(0);
254 10 : bool arg2 = PG_GETARG_BOOL(1);
255 :
256 10 : PG_RETURN_BOOL(arg1 > arg2);
257 : }
258 :
259 : Datum
260 16 : boolle(PG_FUNCTION_ARGS)
261 : {
262 16 : bool arg1 = PG_GETARG_BOOL(0);
263 16 : bool arg2 = PG_GETARG_BOOL(1);
264 :
265 16 : PG_RETURN_BOOL(arg1 <= arg2);
266 : }
267 :
268 : Datum
269 16 : boolge(PG_FUNCTION_ARGS)
270 : {
271 16 : bool arg1 = PG_GETARG_BOOL(0);
272 16 : bool arg2 = PG_GETARG_BOOL(1);
273 :
274 16 : PG_RETURN_BOOL(arg1 >= arg2);
275 : }
276 :
277 : Datum
278 92672 : hashbool(PG_FUNCTION_ARGS)
279 : {
280 92672 : 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 120 : booland_statefunc(PG_FUNCTION_ARGS)
301 : {
302 120 : 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 56 : boolor_statefunc(PG_FUNCTION_ARGS)
313 : {
314 56 : 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 12 : makeBoolAggState(FunctionCallInfo fcinfo)
325 : {
326 : BoolAggState *state;
327 : MemoryContext agg_context;
328 :
329 12 : if (!AggCheckCallContext(fcinfo, &agg_context))
330 0 : elog(ERROR, "aggregate function called in non-aggregate context");
331 :
332 12 : state = (BoolAggState *) MemoryContextAlloc(agg_context,
333 : sizeof(BoolAggState));
334 12 : state->aggcount = 0;
335 12 : state->aggtrue = 0;
336 :
337 12 : return state;
338 : }
339 :
340 : Datum
341 60 : bool_accum(PG_FUNCTION_ARGS)
342 : {
343 : BoolAggState *state;
344 :
345 60 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
346 :
347 : /* Create the state data on first call */
348 60 : if (state == NULL)
349 12 : state = makeBoolAggState(fcinfo);
350 :
351 60 : if (!PG_ARGISNULL(1))
352 : {
353 60 : state->aggcount++;
354 60 : if (PG_GETARG_BOOL(1))
355 36 : state->aggtrue++;
356 : }
357 :
358 60 : PG_RETURN_POINTER(state);
359 : }
360 :
361 : Datum
362 48 : bool_accum_inv(PG_FUNCTION_ARGS)
363 : {
364 : BoolAggState *state;
365 :
366 48 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
367 :
368 : /* bool_accum should have created the state data */
369 48 : if (state == NULL)
370 0 : elog(ERROR, "bool_accum_inv called with NULL state");
371 :
372 48 : if (!PG_ARGISNULL(1))
373 : {
374 48 : state->aggcount--;
375 48 : if (PG_GETARG_BOOL(1))
376 24 : state->aggtrue--;
377 : }
378 :
379 48 : PG_RETURN_POINTER(state);
380 : }
381 :
382 : Datum
383 30 : bool_alltrue(PG_FUNCTION_ARGS)
384 : {
385 : BoolAggState *state;
386 :
387 30 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
388 :
389 : /* if there were no non-null values, return NULL */
390 30 : if (state == NULL || state->aggcount == 0)
391 0 : PG_RETURN_NULL();
392 :
393 : /* true if all non-null values are true */
394 30 : PG_RETURN_BOOL(state->aggtrue == state->aggcount);
395 : }
396 :
397 : Datum
398 30 : bool_anytrue(PG_FUNCTION_ARGS)
399 : {
400 : BoolAggState *state;
401 :
402 30 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
403 :
404 : /* if there were no non-null values, return NULL */
405 30 : if (state == NULL || state->aggcount == 0)
406 0 : PG_RETURN_NULL();
407 :
408 : /* true if any non-null value is true */
409 30 : PG_RETURN_BOOL(state->aggtrue > 0);
410 : }
|