Age Owner TLA 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
5144 peter_e 30 CBC 68431 : parse_bool(const char *value, bool *result)
31 : {
32 68431 : return parse_bool_with_len(value, strlen(value), result);
33 : }
34 :
35 : bool
36 5706525 : parse_bool_with_len(const char *value, size_t len, bool *result)
37 : {
38 5706525 : switch (*value)
39 : {
40 1349101 : case 't':
41 : case 'T':
42 1349101 : if (pg_strncasecmp(value, "true", len) == 0)
43 : {
44 1349095 : if (result)
45 1349095 : *result = true;
46 1349095 : return true;
47 : }
48 6 : break;
49 4311376 : case 'f':
50 : case 'F':
51 4311376 : if (pg_strncasecmp(value, "false", len) == 0)
52 : {
53 4311370 : if (result)
54 4311370 : *result = false;
55 4311370 : return true;
56 : }
57 6 : break;
58 208 : case 'y':
59 : case 'Y':
60 208 : if (pg_strncasecmp(value, "yes", len) == 0)
61 : {
62 205 : if (result)
63 205 : *result = true;
64 205 : return true;
65 : }
66 3 : break;
67 4930 : case 'n':
68 : case 'N':
69 4930 : if (pg_strncasecmp(value, "no", len) == 0)
70 : {
71 4927 : if (result)
72 4927 : *result = false;
73 4927 : return true;
74 : }
75 3 : break;
76 34602 : case 'o':
77 : case 'O':
78 : /* 'o' is not unique enough */
79 34602 : if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
80 : {
81 26613 : if (result)
82 26613 : *result = true;
83 26613 : return true;
84 : }
85 7989 : else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
86 : {
87 7980 : if (result)
88 7980 : *result = false;
89 7980 : return true;
90 : }
91 9 : break;
92 3417 : case '1':
93 3417 : if (len == 1)
94 : {
95 3405 : if (result)
96 3405 : *result = true;
97 3405 : return true;
98 : }
99 12 : break;
100 2867 : case '0':
101 2867 : if (len == 1)
102 : {
103 2864 : if (result)
104 2864 : *result = false;
105 2864 : return true;
106 : }
107 3 : break;
108 24 : default:
109 24 : break;
110 : }
111 :
112 66 : if (result)
5050 bruce 113 66 : *result = false; /* suppress compiler warning */
5144 peter_e 114 66 : 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
8343 tgl 130 5638094 : boolin(PG_FUNCTION_ARGS)
131 : {
5624 bruce 132 5638094 : 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 : */
5791 neilc 140 5638094 : str = in_str;
141 5638136 : while (isspace((unsigned char) *str))
142 42 : str++;
143 :
144 5638094 : len = strlen(str);
145 5638139 : while (len > 0 && isspace((unsigned char) str[len - 1]))
146 45 : len--;
147 :
5144 peter_e 148 5638094 : if (parse_bool_with_len(str, len, &result))
149 5638049 : PG_RETURN_BOOL(result);
150 :
121 tgl 151 GNC 45 : 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 : /*
9345 bruce 158 ECB : * boolout - converts 1 or 0 to "t" or "f"
159 : */
8343 tgl 160 : Datum
8343 tgl 161 CBC 768880 : boolout(PG_FUNCTION_ARGS)
162 : {
163 768880 : bool b = PG_GETARG_BOOL(0);
9344 bruce 164 768880 : char *result = (char *) palloc(2);
9345 bruce 165 ECB :
8343 tgl 166 GIC 768880 : result[0] = (b) ? 't' : 'f';
9345 bruce 167 768880 : result[1] = '\0';
8343 tgl 168 768880 : 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
7272 tgl 175 EUB : * as "true".
176 : */
177 : Datum
7272 tgl 178 UIC 0 : boolrecv(PG_FUNCTION_ARGS)
179 : {
7272 tgl 180 UBC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
7272 tgl 181 EUB : int ext;
182 :
7272 tgl 183 UIC 0 : ext = pq_getmsgbyte(buf);
578 michael 184 0 : PG_RETURN_BOOL(ext != 0);
185 : }
186 :
187 : /*
7272 tgl 188 EUB : * boolsend - converts bool to binary format
189 : */
190 : Datum
7272 tgl 191 UIC 0 : boolsend(PG_FUNCTION_ARGS)
192 : {
7272 tgl 193 UBC 0 : bool arg1 = PG_GETARG_BOOL(0);
7272 tgl 194 EUB : StringInfoData buf;
195 :
7272 tgl 196 UIC 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();
5787 tgl 205 ECB : * this function follows the SQL-spec result (except for producing lower case)
206 : */
5791 neilc 207 : Datum
5791 neilc 208 GIC 63 : booltext(PG_FUNCTION_ARGS)
209 : {
5624 bruce 210 CBC 63 : bool arg1 = PG_GETARG_BOOL(0);
5493 tgl 211 ECB : const char *str;
212 :
5791 neilc 213 CBC 63 : if (arg1)
5791 neilc 214 GIC 27 : str = "true";
5791 neilc 215 ECB : else
5791 neilc 216 GIC 36 : str = "false";
217 :
5493 tgl 218 63 : PG_RETURN_TEXT_P(cstring_to_text(str));
219 : }
220 :
221 :
222 : /*****************************************************************************
223 : * PUBLIC ROUTINES *
9770 scrappy 224 ECB : *****************************************************************************/
225 :
8343 tgl 226 : Datum
8343 tgl 227 CBC 98840 : booleq(PG_FUNCTION_ARGS)
228 : {
229 98840 : bool arg1 = PG_GETARG_BOOL(0);
8343 tgl 230 GIC 98840 : bool arg2 = PG_GETARG_BOOL(1);
231 :
232 98840 : PG_RETURN_BOOL(arg1 == arg2);
9770 scrappy 233 ECB : }
234 :
8343 tgl 235 : Datum
8343 tgl 236 CBC 37761 : boolne(PG_FUNCTION_ARGS)
237 : {
238 37761 : bool arg1 = PG_GETARG_BOOL(0);
8343 tgl 239 GIC 37761 : bool arg2 = PG_GETARG_BOOL(1);
240 :
241 37761 : PG_RETURN_BOOL(arg1 != arg2);
9770 scrappy 242 ECB : }
243 :
8343 tgl 244 : Datum
8343 tgl 245 CBC 5 : boollt(PG_FUNCTION_ARGS)
246 : {
247 5 : bool arg1 = PG_GETARG_BOOL(0);
8343 tgl 248 GIC 5 : bool arg2 = PG_GETARG_BOOL(1);
249 :
250 5 : PG_RETURN_BOOL(arg1 < arg2);
9478 lockhart 251 ECB : }
252 :
8343 tgl 253 : Datum
8343 tgl 254 CBC 5 : boolgt(PG_FUNCTION_ARGS)
255 : {
256 5 : bool arg1 = PG_GETARG_BOOL(0);
8343 tgl 257 GIC 5 : bool arg2 = PG_GETARG_BOOL(1);
258 :
259 5 : PG_RETURN_BOOL(arg1 > arg2);
9478 lockhart 260 ECB : }
261 :
8343 tgl 262 : Datum
8343 tgl 263 CBC 8 : boolle(PG_FUNCTION_ARGS)
264 : {
265 8 : bool arg1 = PG_GETARG_BOOL(0);
8343 tgl 266 GIC 8 : bool arg2 = PG_GETARG_BOOL(1);
267 :
268 8 : PG_RETURN_BOOL(arg1 <= arg2);
8343 tgl 269 ECB : }
270 :
271 : Datum
8343 tgl 272 CBC 8 : boolge(PG_FUNCTION_ARGS)
273 : {
274 8 : bool arg1 = PG_GETARG_BOOL(0);
8343 tgl 275 GIC 8 : bool arg2 = PG_GETARG_BOOL(1);
276 :
277 8 : 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 : *
3283 tgl 288 ECB : * Note: this is only used in plain aggregate mode, not moving-aggregate mode.
289 : */
6797 bruce 290 : Datum
6797 bruce 291 GIC 75 : booland_statefunc(PG_FUNCTION_ARGS)
292 : {
6892 293 75 : 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 : *
3283 tgl 300 ECB : * Note: this is only used in plain aggregate mode, not moving-aggregate mode.
301 : */
6797 bruce 302 : Datum
6797 bruce 303 GIC 28 : boolor_statefunc(PG_FUNCTION_ARGS)
304 : {
6892 305 28 : 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 */
3283 tgl 312 ECB : } BoolAggState;
313 :
314 : static BoolAggState *
3283 tgl 315 GIC 6 : makeBoolAggState(FunctionCallInfo fcinfo)
316 : {
3283 tgl 317 ECB : BoolAggState *state;
3283 tgl 318 EUB : MemoryContext agg_context;
319 :
3283 tgl 320 CBC 6 : if (!AggCheckCallContext(fcinfo, &agg_context))
3283 tgl 321 UIC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
3283 tgl 322 ECB :
3283 tgl 323 CBC 6 : state = (BoolAggState *) MemoryContextAlloc(agg_context,
324 : sizeof(BoolAggState));
325 6 : state->aggcount = 0;
3283 tgl 326 GIC 6 : state->aggtrue = 0;
327 :
328 6 : return state;
3283 tgl 329 ECB : }
330 :
331 : Datum
3283 tgl 332 GIC 30 : bool_accum(PG_FUNCTION_ARGS)
3283 tgl 333 ECB : {
334 : BoolAggState *state;
335 :
3283 tgl 336 CBC 30 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
3283 tgl 337 ECB :
338 : /* Create the state data on first call */
3283 tgl 339 CBC 30 : if (state == NULL)
3283 tgl 340 GIC 6 : state = makeBoolAggState(fcinfo);
3283 tgl 341 ECB :
3283 tgl 342 CBC 30 : if (!PG_ARGISNULL(1))
3283 tgl 343 ECB : {
3283 tgl 344 GIC 30 : state->aggcount++;
345 30 : if (PG_GETARG_BOOL(1))
3283 tgl 346 CBC 18 : state->aggtrue++;
347 : }
348 :
3283 tgl 349 GIC 30 : PG_RETURN_POINTER(state);
3283 tgl 350 ECB : }
351 :
352 : Datum
3283 tgl 353 GIC 24 : bool_accum_inv(PG_FUNCTION_ARGS)
3283 tgl 354 ECB : {
355 : BoolAggState *state;
356 :
3283 tgl 357 CBC 24 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
3283 tgl 358 EUB :
359 : /* bool_accum should have created the state data */
3283 tgl 360 CBC 24 : if (state == NULL)
3283 tgl 361 UIC 0 : elog(ERROR, "bool_accum_inv called with NULL state");
3283 tgl 362 ECB :
3283 tgl 363 CBC 24 : if (!PG_ARGISNULL(1))
3283 tgl 364 ECB : {
3283 tgl 365 GIC 24 : state->aggcount--;
366 24 : if (PG_GETARG_BOOL(1))
3283 tgl 367 CBC 12 : state->aggtrue--;
368 : }
369 :
3283 tgl 370 GIC 24 : PG_RETURN_POINTER(state);
3283 tgl 371 ECB : }
372 :
373 : Datum
3283 tgl 374 GIC 15 : bool_alltrue(PG_FUNCTION_ARGS)
3283 tgl 375 ECB : {
376 : BoolAggState *state;
377 :
3283 tgl 378 CBC 15 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
3283 tgl 379 EUB :
380 : /* if there were no non-null values, return NULL */
3283 tgl 381 GIC 15 : if (state == NULL || state->aggcount == 0)
3283 tgl 382 LBC 0 : PG_RETURN_NULL();
383 :
384 : /* true if all non-null values are true */
3283 tgl 385 GIC 15 : PG_RETURN_BOOL(state->aggtrue == state->aggcount);
3283 tgl 386 ECB : }
387 :
388 : Datum
3283 tgl 389 GIC 15 : bool_anytrue(PG_FUNCTION_ARGS)
3283 tgl 390 ECB : {
391 : BoolAggState *state;
392 :
3283 tgl 393 CBC 15 : state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
3283 tgl 394 EUB :
395 : /* if there were no non-null values, return NULL */
3283 tgl 396 GIC 15 : if (state == NULL || state->aggcount == 0)
3283 tgl 397 LBC 0 : PG_RETURN_NULL();
398 :
399 : /* true if any non-null value is true */
3283 tgl 400 GIC 15 : PG_RETURN_BOOL(state->aggtrue > 0);
401 : }
|