diff options
Diffstat (limited to 'src/backend/utils/adt/bool.c')
-rw-r--r-- | src/backend/utils/adt/bool.c | 109 |
1 files changed, 105 insertions, 4 deletions
diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c index d419b4a7a66..3d2f268961f 100644 --- a/src/backend/utils/adt/bool.c +++ b/src/backend/utils/adt/bool.c @@ -283,8 +283,11 @@ boolge(PG_FUNCTION_ARGS) * 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. +/* + * 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) @@ -292,11 +295,109 @@ 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. - * must be strict. The name of the aggregate is bool_or. See the doc. +/* + * 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); +} |