1 /*-------------------------------------------------------------------------
2 *
3 * bool.c
4 * Functions for the built-in type "bool".
5 *
6 * Portions Copyright (c) 1996-2018, 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
parse_bool(const char * value,bool * result)30 parse_bool(const char *value, bool *result)
31 {
32 return parse_bool_with_len(value, strlen(value), result);
33 }
34
35 bool
parse_bool_with_len(const char * value,size_t len,bool * result)36 parse_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 */
129 Datum
boolin(PG_FUNCTION_ARGS)130 boolin(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 */
163 Datum
boolout(PG_FUNCTION_ARGS)164 boolout(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 */
180 Datum
boolrecv(PG_FUNCTION_ARGS)181 boolrecv(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 */
193 Datum
boolsend(PG_FUNCTION_ARGS)194 boolsend(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 */
210 Datum
booltext(PG_FUNCTION_ARGS)211 booltext(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
229 Datum
booleq(PG_FUNCTION_ARGS)230 booleq(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
238 Datum
boolne(PG_FUNCTION_ARGS)239 boolne(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
247 Datum
boollt(PG_FUNCTION_ARGS)248 boollt(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
256 Datum
boolgt(PG_FUNCTION_ARGS)257 boolgt(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
265 Datum
boolle(PG_FUNCTION_ARGS)266 boolle(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
274 Datum
boolge(PG_FUNCTION_ARGS)275 boolge(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 */
293 Datum
booland_statefunc(PG_FUNCTION_ARGS)294 booland_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 */
305 Datum
boolor_statefunc(PG_FUNCTION_ARGS)306 boolor_statefunc(PG_FUNCTION_ARGS)
307 {
308 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 *
makeBoolAggState(FunctionCallInfo fcinfo)318 makeBoolAggState(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
334 Datum
bool_accum(PG_FUNCTION_ARGS)335 bool_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
355 Datum
bool_accum_inv(PG_FUNCTION_ARGS)356 bool_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
376 Datum
bool_alltrue(PG_FUNCTION_ARGS)377 bool_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
391 Datum
bool_anytrue(PG_FUNCTION_ARGS)392 bool_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