1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* bool.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Functions for the built-in type "bool".
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2016-01-02 19:33:40 +01:00
|
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/bool.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1996-11-03 07:54:38 +01:00
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2007-06-02 01:40:19 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
#include "libpq/pqformat.h"
|
1999-07-16 05:14:30 +02:00
|
|
|
#include "utils/builtins.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2009-03-09 15:34:35 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2009-03-09 17:49:12 +01:00
|
|
|
if (result)
|
2009-06-11 16:49:15 +02:00
|
|
|
*result = false; /* suppress compiler warning */
|
2009-03-09 15:34:35 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* USER I/O ROUTINES *
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* boolin - converts "t" or "f" to 1 or 0
|
1997-10-09 07:06:12 +02:00
|
|
|
*
|
2009-03-09 15:34:35 +01:00
|
|
|
* Check explicitly for "true/false" and TRUE/FALSE, 1/0, YES/NO, ON/OFF.
|
|
|
|
* Reject other values.
|
1997-10-17 07:38:32 +02:00
|
|
|
*
|
|
|
|
* In the switch statement, check the most-used possibilities first.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
boolin(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
const char *in_str = PG_GETARG_CSTRING(0);
|
|
|
|
const char *str;
|
|
|
|
size_t len;
|
2009-03-09 15:34:35 +01:00
|
|
|
bool result;
|
2007-06-02 01:40:19 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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--;
|
|
|
|
|
2009-03-09 15:34:35 +01:00
|
|
|
if (parse_bool_with_len(str, len, &result))
|
|
|
|
PG_RETURN_BOOL(result);
|
1997-10-17 07:38:32 +02:00
|
|
|
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2007-11-15 22:14:46 +01:00
|
|
|
errmsg("invalid input syntax for type boolean: \"%s\"", in_str)));
|
2000-06-05 09:29:25 +02:00
|
|
|
|
1997-11-07 07:30:20 +01:00
|
|
|
/* not reached */
|
2000-06-05 09:29:25 +02:00
|
|
|
PG_RETURN_BOOL(false);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* boolout - converts 1 or 0 to "t" or "f"
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
boolout(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
bool b = PG_GETARG_BOOL(0);
|
1997-09-08 04:41:22 +02:00
|
|
|
char *result = (char *) palloc(2);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
result[0] = (b) ? 't' : 'f';
|
1997-09-07 07:04:48 +02:00
|
|
|
result[1] = '\0';
|
2000-06-05 09:29:25 +02:00
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* 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));
|
|
|
|
}
|
|
|
|
|
2007-06-02 01:40:19 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* booltext - cast function for bool => text
|
2007-06-05 23:31:09 +02:00
|
|
|
*
|
|
|
|
* We need this because it's different from the behavior of boolout();
|
|
|
|
* this function follows the SQL-spec result (except for producing lower case)
|
2007-06-02 01:40:19 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
booltext(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
bool arg1 = PG_GETARG_BOOL(0);
|
2008-03-25 23:42:46 +01:00
|
|
|
const char *str;
|
2007-06-02 01:40:19 +02:00
|
|
|
|
|
|
|
if (arg1)
|
|
|
|
str = "true";
|
|
|
|
else
|
|
|
|
str = "false";
|
|
|
|
|
2008-03-25 23:42:46 +01:00
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(str));
|
2007-06-02 01:40:19 +02:00
|
|
|
}
|
|
|
|
|
1997-11-07 07:30:20 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* PUBLIC ROUTINES *
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
booleq(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
bool arg1 = PG_GETARG_BOOL(0);
|
|
|
|
bool arg2 = PG_GETARG_BOOL(1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(arg1 == arg2);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
boolne(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
bool arg1 = PG_GETARG_BOOL(0);
|
|
|
|
bool arg2 = PG_GETARG_BOOL(1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(arg1 != arg2);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
boollt(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
bool arg1 = PG_GETARG_BOOL(0);
|
|
|
|
bool arg2 = PG_GETARG_BOOL(1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(arg1 < arg2);
|
1997-04-27 21:20:16 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
boolgt(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
bool arg1 = PG_GETARG_BOOL(0);
|
|
|
|
bool arg2 = PG_GETARG_BOOL(1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(arg1 > arg2);
|
1997-04-27 21:20:16 +02:00
|
|
|
}
|
1997-10-30 17:45:12 +01:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2004-05-26 17:26:28 +02:00
|
|
|
/*
|
|
|
|
* boolean-and and boolean-or aggregates.
|
|
|
|
*/
|
|
|
|
|
2014-04-13 06:01:46 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
2004-05-26 17:26:28 +02:00
|
|
|
*/
|
2004-08-29 07:07:03 +02:00
|
|
|
Datum
|
|
|
|
booland_statefunc(PG_FUNCTION_ARGS)
|
2004-05-26 17:26:28 +02:00
|
|
|
{
|
|
|
|
PG_RETURN_BOOL(PG_GETARG_BOOL(0) && PG_GETARG_BOOL(1));
|
|
|
|
}
|
|
|
|
|
2014-04-13 06:01:46 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
2004-05-26 17:26:28 +02:00
|
|
|
*/
|
2004-08-29 07:07:03 +02:00
|
|
|
Datum
|
|
|
|
boolor_statefunc(PG_FUNCTION_ARGS)
|
2004-05-26 17:26:28 +02:00
|
|
|
{
|
|
|
|
PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1));
|
|
|
|
}
|
2014-04-13 06:01:46 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|