* bool.c
* Functions for the built-in type "bool".
*
- * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/bool.c,v 1.36 2004/12/31 22:01:21 pgsql Exp $
+ * src/backend/utils/adt/bool.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include <ctype.h>
+
#include "libpq/pqformat.h"
#include "utils/builtins.h"
-/*****************************************************************************
- * 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.
- * Reject other values. - thomas 1997-10-05
- *
- * In the switch statement, check the most-used possibilities first.
+ * 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.
*/
-Datum
-boolin(PG_FUNCTION_ARGS)
+bool
+parse_bool(const char *value, bool *result)
{
- char *b = PG_GETARG_CSTRING(0);
+ return parse_bool_with_len(value, strlen(value), result);
+}
- switch (*b)
+bool
+parse_bool_with_len(const char *value, size_t len, bool *result)
+{
+ switch (*value)
{
case 't':
case 'T':
- if (pg_strncasecmp(b, "true", strlen(b)) == 0)
- PG_RETURN_BOOL(true);
+ if (pg_strncasecmp(value, "true", len) == 0)
+ {
+ if (result)
+ *result = true;
+ return true;
+ }
break;
-
case 'f':
case 'F':
- if (pg_strncasecmp(b, "false", strlen(b)) == 0)
- PG_RETURN_BOOL(false);
+ if (pg_strncasecmp(value, "false", len) == 0)
+ {
+ if (result)
+ *result = false;
+ return true;
+ }
break;
-
case 'y':
case 'Y':
- if (pg_strncasecmp(b, "yes", strlen(b)) == 0)
- PG_RETURN_BOOL(true);
- break;
-
- case '1':
- if (pg_strncasecmp(b, "1", strlen(b)) == 0)
- PG_RETURN_BOOL(true);
+ if (pg_strncasecmp(value, "yes", len) == 0)
+ {
+ if (result)
+ *result = true;
+ return true;
+ }
break;
-
case 'n':
case 'N':
- if (pg_strncasecmp(b, "no", strlen(b)) == 0)
- PG_RETURN_BOOL(false);
+ 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 (pg_strncasecmp(b, "0", strlen(b)) == 0)
- PG_RETURN_BOOL(false);
+ 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 boolean: \"%s\"", b)));
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ "boolean", in_str)));
/* not reached */
PG_RETURN_BOOL(false);
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 *
}
/*
- * Per SQL92, istrue() and isfalse() should return false, not NULL,
- * when presented a NULL input (since NULL is our implementation of
- * UNKNOWN). Conversely isnottrue() and isnotfalse() should return true.
- * Therefore, these routines are all declared not-strict in pg_proc
- * and must do their own checking for null inputs.
+ * 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 we don't need isunknown() and isnotunknown() functions, since
- * nullvalue() and nonnullvalue() will serve.
+ * 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
-istrue(PG_FUNCTION_ARGS)
+boolor_statefunc(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1));
+}
+
+typedef struct BoolAggState
{
- bool b;
+ int64 aggcount; /* number of non-null values aggregated */
+ int64 aggtrue; /* number of values aggregated that are true */
+} BoolAggState;
- if (PG_ARGISNULL(0))
- PG_RETURN_BOOL(false);
+static BoolAggState *
+makeBoolAggState(FunctionCallInfo fcinfo)
+{
+ BoolAggState *state;
+ MemoryContext agg_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
- b = PG_GETARG_BOOL(0);
+ state = (BoolAggState *) MemoryContextAlloc(agg_context,
+ sizeof(BoolAggState));
+ state->aggcount = 0;
+ state->aggtrue = 0;
- PG_RETURN_BOOL(b);
+ return state;
}
Datum
-isfalse(PG_FUNCTION_ARGS)
+bool_accum(PG_FUNCTION_ARGS)
{
- bool b;
+ BoolAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
- if (PG_ARGISNULL(0))
- PG_RETURN_BOOL(false);
+ /* Create the state data on first call */
+ if (state == NULL)
+ state = makeBoolAggState(fcinfo);
- b = PG_GETARG_BOOL(0);
+ if (!PG_ARGISNULL(1))
+ {
+ state->aggcount++;
+ if (PG_GETARG_BOOL(1))
+ state->aggtrue++;
+ }
- PG_RETURN_BOOL(!b);
+ PG_RETURN_POINTER(state);
}
Datum
-isnottrue(PG_FUNCTION_ARGS)
+bool_accum_inv(PG_FUNCTION_ARGS)
{
- bool b;
+ BoolAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
- if (PG_ARGISNULL(0))
- PG_RETURN_BOOL(true);
+ /* bool_accum should have created the state data */
+ if (state == NULL)
+ elog(ERROR, "bool_accum_inv called with NULL state");
- b = PG_GETARG_BOOL(0);
+ if (!PG_ARGISNULL(1))
+ {
+ state->aggcount--;
+ if (PG_GETARG_BOOL(1))
+ state->aggtrue--;
+ }
- PG_RETURN_BOOL(!b);
+ PG_RETURN_POINTER(state);
}
Datum
-isnotfalse(PG_FUNCTION_ARGS)
+bool_alltrue(PG_FUNCTION_ARGS)
{
- bool b;
+ BoolAggState *state;
- if (PG_ARGISNULL(0))
- PG_RETURN_BOOL(true);
+ state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0);
- b = PG_GETARG_BOOL(0);
+ /* if there were no non-null values, return NULL */
+ if (state == NULL || state->aggcount == 0)
+ PG_RETURN_NULL();
- PG_RETURN_BOOL(b);
+ /* true if all non-null values are true */
+ PG_RETURN_BOOL(state->aggtrue == state->aggcount);
}
-/*
- * boolean-and and boolean-or aggregates.
- */
-
-/* function for standard EVERY aggregate implementation conforming to SQL 2003.
- * must be strict. It is also named bool_and for homogeneity.
- */
Datum
-booland_statefunc(PG_FUNCTION_ARGS)
+bool_anytrue(PG_FUNCTION_ARGS)
{
- PG_RETURN_BOOL(PG_GETARG_BOOL(0) && PG_GETARG_BOOL(1));
-}
+ BoolAggState *state;
-/* function for standard ANY/SOME aggregate conforming to SQL 2003.
- * must be strict. The name of the aggregate is bool_or. See the doc.
- */
-Datum
-boolor_statefunc(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1));
+ 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);
}