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