]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/bool.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / bool.c
index 152221ab43f72578cd4ac0ba59885808434364f0..6c87e211407d5e506e5b0ebf7083f182a5c6d95d 100644 (file)
  * bool.c
  *       Functions for the built-in type "bool".
  *
- * Portions Copyright (c) 1996-2006, 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.37 2006/03/05 15:58:41 momjian 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);
@@ -127,6 +201,26 @@ boolsend(PG_FUNCTION_ARGS)
        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                                                                                                                 *
@@ -187,86 +281,124 @@ boolge(PG_FUNCTION_ARGS)
 }
 
 /*
- * 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);
 }