]> 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 d0ac12f4f261ed6672dccdf783d60c90816fb68c..6c87e211407d5e506e5b0ebf7083f182a5c6d95d 100644 (file)
  * bool.c
  *       Functions for the built-in type "bool".
  *
- * Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/bool.c,v 1.17 1999/07/14 01:19:56 momjian Exp $
+ *       src/backend/utils/adt/bool.c
  *
  *-------------------------------------------------------------------------
  */
 
-#include <string.h>
 #include "postgres.h"
 
-#include "utils/builtins.h"            /* where the declarations go */
-#include "utils/palloc.h"
-#include "utils/mcxt.h"
+#include <ctype.h>
 
-/*****************************************************************************
- *      USER I/O ROUTINES                                                                                                               *
- *****************************************************************************/
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
 
 /*
- *             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.
  */
 bool
-boolin(char *b)
+parse_bool(const char *value, bool *result)
 {
-       switch (*b)
+       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 (strncasecmp(b, "true", strlen(b)) == 0)
-                               return TRUE;
+               case 't':
+               case 'T':
+                       if (pg_strncasecmp(value, "true", len) == 0)
+                       {
+                               if (result)
+                                       *result = true;
+                               return true;
+                       }
                        break;
-
                case 'f':
                case 'F':
-                       if (strncasecmp(b, "false", strlen(b)) == 0)
-                               return FALSE;
+                       if (pg_strncasecmp(value, "false", len) == 0)
+                       {
+                               if (result)
+                                       *result = false;
+                               return true;
+                       }
                        break;
-
                case 'y':
                case 'Y':
-                       if (strncasecmp(b, "yes", strlen(b)) == 0)
-                               return TRUE;
+                       if (pg_strncasecmp(value, "yes", len) == 0)
+                       {
+                               if (result)
+                                       *result = true;
+                               return true;
+                       }
                        break;
-
-               case '1':
-                       if (strncasecmp(b, "1", strlen(b)) == 0)
-                               return TRUE;
-                       break;
-
                case 'n':
                case 'N':
-                       if (strncasecmp(b, "no", strlen(b)) == 0)
-                               return 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 (strncasecmp(b, "0", strlen(b)) == 0)
-                               return FALSE;
+                       if (len == 1)
+                       {
+                               if (result)
+                                       *result = false;
+                               return true;
+                       }
                        break;
-
                default:
                        break;
        }
 
-       elog(ERROR, "Bad boolean external representation '%s'", b);
+       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 */
-       return FALSE;
-}      /* boolin() */
+       PG_RETURN_BOOL(false);
+}
 
 /*
  *             boolout                 - converts 1 or 0 to "t" or "f"
  */
-char *
-boolout(bool b)
+Datum
+boolout(PG_FUNCTION_ARGS)
 {
+       bool            b = PG_GETARG_BOOL(0);
        char       *result = (char *) palloc(2);
 
-       *result = (b) ? 't' : 'f';
+       result[0] = (b) ? 't' : 'f';
        result[1] = '\0';
-       return result;
-}      /* boolout() */
+       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                                                                                                                 *
  *****************************************************************************/
 
-bool
-booleq(bool arg1, bool arg2)
+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)
 {
-       return arg1 == arg2;
+       bool            arg1 = PG_GETARG_BOOL(0);
+       bool            arg2 = PG_GETARG_BOOL(1);
+
+       PG_RETURN_BOOL(arg1 != arg2);
 }
 
-bool
-boolne(bool arg1, bool arg2)
+Datum
+boollt(PG_FUNCTION_ARGS)
 {
-       return arg1 != arg2;
+       bool            arg1 = PG_GETARG_BOOL(0);
+       bool            arg2 = PG_GETARG_BOOL(1);
+
+       PG_RETURN_BOOL(arg1 < arg2);
 }
 
-bool
-boollt(bool arg1, bool arg2)
+Datum
+boolgt(PG_FUNCTION_ARGS)
 {
-       return arg1 < arg2;
+       bool            arg1 = PG_GETARG_BOOL(0);
+       bool            arg2 = PG_GETARG_BOOL(1);
+
+       PG_RETURN_BOOL(arg1 > arg2);
 }
 
-bool
-boolgt(bool arg1, bool arg2)
+Datum
+boolle(PG_FUNCTION_ARGS)
 {
-       return arg1 > arg2;
+       bool            arg1 = PG_GETARG_BOOL(0);
+       bool            arg2 = PG_GETARG_BOOL(1);
+
+       PG_RETURN_BOOL(arg1 <= arg2);
 }
 
-bool
-istrue(bool arg1)
+Datum
+boolge(PG_FUNCTION_ARGS)
 {
-       return arg1 == TRUE;
-}      /* istrue() */
+       bool            arg1 = PG_GETARG_BOOL(0);
+       bool            arg2 = PG_GETARG_BOOL(1);
 
-bool
-isfalse(bool arg1)
+       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
 {
-       return arg1 != TRUE;
-}      /* isfalse() */
+       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);
+}