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