1/*-------------------------------------------------------------------------
2 *
3 * bool.c
4 * Functions for the built-in type "bool".
5 *
6 * Portions Copyright (c) 1996-2019, 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 */
29bool
30parse_bool(const char *value, bool *result)
31{
32 return parse_bool_with_len(value, strlen(value), result);
33}
34
35bool
36parse_bool_with_len(const char *value, size_t len, bool *result)
37{
38 switch (*value)
39 {
40 case 't':
41 case 'T':
42 if (pg_strncasecmp(value, "true", len) == 0)
43 {
44 if (result)
45 *result = true;
46 return true;
47 }
48 break;
49 case 'f':
50 case 'F':
51 if (pg_strncasecmp(value, "false", len) == 0)
52 {
53 if (result)
54 *result = false;
55 return true;
56 }
57 break;
58 case 'y':
59 case 'Y':
60 if (pg_strncasecmp(value, "yes", len) == 0)
61 {
62 if (result)
63 *result = true;
64 return true;
65 }
66 break;
67 case 'n':
68 case 'N':
69 if (pg_strncasecmp(value, "no", len) == 0)
70 {
71 if (result)
72 *result = false;
73 return true;
74 }
75 break;
76 case 'o':
77 case 'O':
78 /* 'o' is not unique enough */
79 if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
80 {
81 if (result)
82 *result = true;
83 return true;
84 }
85 else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
86 {
87 if (result)
88 *result = false;
89 return true;
90 }
91 break;
92 case '1':
93 if (len == 1)
94 {
95 if (result)
96 *result = true;
97 return true;
98 }
99 break;
100 case '0':
101 if (len == 1)
102 {
103 if (result)
104 *result = false;
105 return true;
106 }
107 break;
108 default:
109 break;
110 }
111
112 if (result)
113 *result = false; /* suppress compiler warning */
114 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 */
129Datum
130boolin(PG_FUNCTION_ARGS)
131{
132 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 str = in_str;
141 while (isspace((unsigned char) *str))
142 str++;
143
144 len = strlen(str);
145 while (len > 0 && isspace((unsigned char) str[len - 1]))
146 len--;
147
148 if (parse_bool_with_len(str, len, &result))
149 PG_RETURN_BOOL(result);
150
151 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 */
163Datum
164boolout(PG_FUNCTION_ARGS)
165{
166 bool b = PG_GETARG_BOOL(0);
167 char *result = (char *) palloc(2);
168
169 result[0] = (b) ? 't' : 'f';
170 result[1] = '\0';
171 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 */
180Datum
181boolrecv(PG_FUNCTION_ARGS)
182{
183 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
184 int ext;
185
186 ext = pq_getmsgbyte(buf);
187 PG_RETURN_BOOL((ext != 0) ? true : false);
188}
189
190/*
191 * boolsend - converts bool to binary format
192 */
193Datum
194boolsend(PG_FUNCTION_ARGS)
195{
196 bool arg1 = PG_GETARG_BOOL(0);
197 StringInfoData buf;
198
199 pq_begintypsend(&buf);
200 pq_sendbyte(&buf, arg1 ? 1 : 0);
201 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 */
210Datum
211booltext(PG_FUNCTION_ARGS)
212{
213 bool arg1 = PG_GETARG_BOOL(0);
214 const char *str;
215
216 if (arg1)
217 str = "true";
218 else
219 str = "false";
220
221 PG_RETURN_TEXT_P(cstring_to_text(str));
222}
223
224
225/*****************************************************************************
226 * PUBLIC ROUTINES *
227 *****************************************************************************/
228
229Datum
230booleq(PG_FUNCTION_ARGS)
231{
232 bool arg1 = PG_GETARG_BOOL(0);
233 bool arg2 = PG_GETARG_BOOL(1);
234
235 PG_RETURN_BOOL(arg1 == arg2);
236}
237
238Datum
239boolne(PG_FUNCTION_ARGS)
240{
241 bool arg1 = PG_GETARG_BOOL(0);
242 bool arg2 = PG_GETARG_BOOL(1);
243
244 PG_RETURN_BOOL(arg1 != arg2);
245}
246
247Datum
248boollt(PG_FUNCTION_ARGS)
249{
250 bool arg1 = PG_GETARG_BOOL(0);
251 bool arg2 = PG_GETARG_BOOL(1);
252
253 PG_RETURN_BOOL(arg1 < arg2);
254}
255
256Datum
257boolgt(PG_FUNCTION_ARGS)
258{
259 bool arg1 = PG_GETARG_BOOL(0);
260 bool arg2 = PG_GETARG_BOOL(1);
261
262 PG_RETURN_BOOL(arg1 > arg2);
263}
264
265Datum
266boolle(PG_FUNCTION_ARGS)
267{
268 bool arg1 = PG_GETARG_BOOL(0);
269 bool arg2 = PG_GETARG_BOOL(1);
270
271 PG_RETURN_BOOL(arg1 <= arg2);
272}
273
274Datum
275boolge(PG_FUNCTION_ARGS)
276{
277 bool arg1 = PG_GETARG_BOOL(0);
278 bool arg2 = PG_GETARG_BOOL(1);
279
280 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 */
293Datum
294booland_statefunc(PG_FUNCTION_ARGS)
295{
296 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 */
305Datum
306boolor_statefunc(PG_FUNCTION_ARGS)
307{
308 PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1));
309}
310
311typedef 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
317static BoolAggState *
318makeBoolAggState(FunctionCallInfo fcinfo)
319{
320 BoolAggState *state;
321 MemoryContext agg_context;
322
323 if (!AggCheckCallContext(fcinfo, &agg_context))
324 elog(ERROR, "aggregate function called in non-aggregate context");
325
326 state = (BoolAggState *) MemoryContextAlloc(agg_context,
327 sizeof(BoolAggState));
328 state->aggcount = 0;
329 state->aggtrue = 0;
330
331 return state;
332}
333
334Datum
335bool_accum(PG_FUNCTION_ARGS)
336{
337 BoolAggState *state;
338
339 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
340
341 /* Create the state data on first call */
342 if (state == NULL)
343 state = makeBoolAggState(fcinfo);
344
345 if (!PG_ARGISNULL(1))
346 {
347 state->aggcount++;
348 if (PG_GETARG_BOOL(1))
349 state->aggtrue++;
350 }
351
352 PG_RETURN_POINTER(state);
353}
354
355Datum
356bool_accum_inv(PG_FUNCTION_ARGS)
357{
358 BoolAggState *state;
359
360 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
361
362 /* bool_accum should have created the state data */
363 if (state == NULL)
364 elog(ERROR, "bool_accum_inv called with NULL state");
365
366 if (!PG_ARGISNULL(1))
367 {
368 state->aggcount--;
369 if (PG_GETARG_BOOL(1))
370 state->aggtrue--;
371 }
372
373 PG_RETURN_POINTER(state);
374}
375
376Datum
377bool_alltrue(PG_FUNCTION_ARGS)
378{
379 BoolAggState *state;
380
381 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
382
383 /* if there were no non-null values, return NULL */
384 if (state == NULL || state->aggcount == 0)
385 PG_RETURN_NULL();
386
387 /* true if all non-null values are true */
388 PG_RETURN_BOOL(state->aggtrue == state->aggcount);
389}
390
391Datum
392bool_anytrue(PG_FUNCTION_ARGS)
393{
394 BoolAggState *state;
395
396 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
397
398 /* if there were no non-null values, return NULL */
399 if (state == NULL || state->aggcount == 0)
400 PG_RETURN_NULL();
401
402 /* true if any non-null value is true */
403 PG_RETURN_BOOL(state->aggtrue > 0);
404}
405