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