diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
commit | 46651ce6fe013220ed397add242004d764fc0153 (patch) | |
tree | 6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/backend/utils/adt/bool.c | |
parent | Initial commit. (diff) | |
download | postgresql-14-upstream.tar.xz postgresql-14-upstream.zip |
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/utils/adt/bool.c')
-rw-r--r-- | src/backend/utils/adt/bool.c | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c new file mode 100644 index 0000000..fe11d1a --- /dev/null +++ b/src/backend/utils/adt/bool.c @@ -0,0 +1,404 @@ +/*------------------------------------------------------------------------- + * + * bool.c + * Functions for the built-in type "bool". + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/bool.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include <ctype.h> + +#include "libpq/pqformat.h" +#include "utils/builtins.h" + +/* + * Try to interpret value as boolean value. Valid values are: true, + * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof. + * If the string parses okay, return true, else false. + * If okay and result is not NULL, return the value in *result. + */ +bool +parse_bool(const char *value, bool *result) +{ + return parse_bool_with_len(value, strlen(value), result); +} + +bool +parse_bool_with_len(const char *value, size_t len, bool *result) +{ + switch (*value) + { + case 't': + case 'T': + if (pg_strncasecmp(value, "true", len) == 0) + { + if (result) + *result = true; + return true; + } + break; + case 'f': + case 'F': + if (pg_strncasecmp(value, "false", len) == 0) + { + if (result) + *result = false; + return true; + } + break; + case 'y': + case 'Y': + if (pg_strncasecmp(value, "yes", len) == 0) + { + if (result) + *result = true; + return true; + } + break; + case 'n': + case 'N': + if (pg_strncasecmp(value, "no", len) == 0) + { + if (result) + *result = false; + return true; + } + break; + case 'o': + case 'O': + /* 'o' is not unique enough */ + if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0) + { + if (result) + *result = true; + return true; + } + else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0) + { + if (result) + *result = false; + return true; + } + break; + case '1': + if (len == 1) + { + if (result) + *result = true; + return true; + } + break; + case '0': + if (len == 1) + { + if (result) + *result = false; + return true; + } + break; + default: + break; + } + + if (result) + *result = false; /* suppress compiler warning */ + return false; +} + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* + * boolin - converts "t" or "f" to 1 or 0 + * + * Check explicitly for "true/false" and TRUE/FALSE, 1/0, YES/NO, ON/OFF. + * Reject other values. + * + * In the switch statement, check the most-used possibilities first. + */ +Datum +boolin(PG_FUNCTION_ARGS) +{ + const char *in_str = PG_GETARG_CSTRING(0); + const char *str; + size_t len; + bool result; + + /* + * Skip leading and trailing whitespace + */ + str = in_str; + while (isspace((unsigned char) *str)) + str++; + + len = strlen(str); + while (len > 0 && isspace((unsigned char) str[len - 1])) + len--; + + if (parse_bool_with_len(str, len, &result)) + PG_RETURN_BOOL(result); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "boolean", in_str))); + + /* not reached */ + PG_RETURN_BOOL(false); +} + +/* + * boolout - converts 1 or 0 to "t" or "f" + */ +Datum +boolout(PG_FUNCTION_ARGS) +{ + bool b = PG_GETARG_BOOL(0); + char *result = (char *) palloc(2); + + result[0] = (b) ? 't' : 'f'; + result[1] = '\0'; + PG_RETURN_CSTRING(result); +} + +/* + * boolrecv - converts external binary format to bool + * + * The external representation is one byte. Any nonzero value is taken + * as "true". + */ +Datum +boolrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + int ext; + + ext = pq_getmsgbyte(buf); + PG_RETURN_BOOL((ext != 0) ? true : false); +} + +/* + * boolsend - converts bool to binary format + */ +Datum +boolsend(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendbyte(&buf, arg1 ? 1 : 0); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + +/* + * booltext - cast function for bool => text + * + * We need this because it's different from the behavior of boolout(); + * this function follows the SQL-spec result (except for producing lower case) + */ +Datum +booltext(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + const char *str; + + if (arg1) + str = "true"; + else + str = "false"; + + PG_RETURN_TEXT_P(cstring_to_text(str)); +} + + +/***************************************************************************** + * PUBLIC ROUTINES * + *****************************************************************************/ + +Datum +booleq(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 == arg2); +} + +Datum +boolne(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 != arg2); +} + +Datum +boollt(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 < arg2); +} + +Datum +boolgt(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 > arg2); +} + +Datum +boolle(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 <= arg2); +} + +Datum +boolge(PG_FUNCTION_ARGS) +{ + bool arg1 = PG_GETARG_BOOL(0); + bool arg2 = PG_GETARG_BOOL(1); + + PG_RETURN_BOOL(arg1 >= arg2); +} + +/* + * boolean-and and boolean-or aggregates. + */ + +/* + * Function for standard EVERY aggregate conforming to SQL 2003. + * The aggregate is also named bool_and for consistency. + * + * Note: this is only used in plain aggregate mode, not moving-aggregate mode. + */ +Datum +booland_statefunc(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(PG_GETARG_BOOL(0) && PG_GETARG_BOOL(1)); +} + +/* + * Function for standard ANY/SOME aggregate conforming to SQL 2003. + * The aggregate is named bool_or, because ANY/SOME have parsing conflicts. + * + * Note: this is only used in plain aggregate mode, not moving-aggregate mode. + */ +Datum +boolor_statefunc(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1)); +} + +typedef struct BoolAggState +{ + int64 aggcount; /* number of non-null values aggregated */ + int64 aggtrue; /* number of values aggregated that are true */ +} BoolAggState; + +static BoolAggState * +makeBoolAggState(FunctionCallInfo fcinfo) +{ + BoolAggState *state; + MemoryContext agg_context; + + if (!AggCheckCallContext(fcinfo, &agg_context)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + state = (BoolAggState *) MemoryContextAlloc(agg_context, + sizeof(BoolAggState)); + state->aggcount = 0; + state->aggtrue = 0; + + return state; +} + +Datum +bool_accum(PG_FUNCTION_ARGS) +{ + BoolAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); + + /* Create the state data on first call */ + if (state == NULL) + state = makeBoolAggState(fcinfo); + + if (!PG_ARGISNULL(1)) + { + state->aggcount++; + if (PG_GETARG_BOOL(1)) + state->aggtrue++; + } + + PG_RETURN_POINTER(state); +} + +Datum +bool_accum_inv(PG_FUNCTION_ARGS) +{ + BoolAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); + + /* bool_accum should have created the state data */ + if (state == NULL) + elog(ERROR, "bool_accum_inv called with NULL state"); + + if (!PG_ARGISNULL(1)) + { + state->aggcount--; + if (PG_GETARG_BOOL(1)) + state->aggtrue--; + } + + PG_RETURN_POINTER(state); +} + +Datum +bool_alltrue(PG_FUNCTION_ARGS) +{ + BoolAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); + + /* if there were no non-null values, return NULL */ + if (state == NULL || state->aggcount == 0) + PG_RETURN_NULL(); + + /* true if all non-null values are true */ + PG_RETURN_BOOL(state->aggtrue == state->aggcount); +} + +Datum +bool_anytrue(PG_FUNCTION_ARGS) +{ + BoolAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); + + /* if there were no non-null values, return NULL */ + if (state == NULL || state->aggcount == 0) + PG_RETURN_NULL(); + + /* true if any non-null value is true */ + PG_RETURN_BOOL(state->aggtrue > 0); +} |