Commit d95425c8 authored by Tom Lane's avatar Tom Lane

Provide moving-aggregate support for boolean aggregates.

David Rowley and Florian Pflug, reviewed by Dean Rasheed
parent 842faa71
...@@ -283,8 +283,11 @@ boolge(PG_FUNCTION_ARGS) ...@@ -283,8 +283,11 @@ boolge(PG_FUNCTION_ARGS)
* boolean-and and boolean-or aggregates. * 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 Datum
booland_statefunc(PG_FUNCTION_ARGS) booland_statefunc(PG_FUNCTION_ARGS)
...@@ -292,11 +295,109 @@ 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)); 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 Datum
boolor_statefunc(PG_FUNCTION_ARGS) boolor_statefunc(PG_FUNCTION_ARGS)
{ {
PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1)); 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);
}
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201404122 #define CATALOG_VERSION_NO 201404123
#endif #endif
...@@ -248,9 +248,9 @@ DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp - - - 0 102 ...@@ -248,9 +248,9 @@ DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp - - - 0 102
DATA(insert ( 2829 n 0 float8_regr_accum float8_corr - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); DATA(insert ( 2829 n 0 float8_regr_accum float8_corr - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
/* boolean-and and boolean-or */ /* boolean-and and boolean-or */
DATA(insert ( 2517 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); DATA(insert ( 2517 n 0 booland_statefunc - bool_accum bool_accum_inv bool_alltrue 58 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2518 n 0 boolor_statefunc - - - - 59 16 0 0 0 _null_ _null_ )); DATA(insert ( 2518 n 0 boolor_statefunc - bool_accum bool_accum_inv bool_anytrue 59 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2519 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); DATA(insert ( 2519 n 0 booland_statefunc - bool_accum bool_accum_inv bool_alltrue 58 16 0 2281 16 _null_ _null_ ));
/* bitwise integer */ /* bitwise integer */
DATA(insert ( 2236 n 0 int2and - - - - 0 21 0 0 0 _null_ _null_ )); DATA(insert ( 2236 n 0 int2and - - - - 0 21 0 0 0 _null_ _null_ ));
......
...@@ -3915,6 +3915,14 @@ DATA(insert OID = 2515 ( booland_statefunc PGNSP PGUID 12 1 0 0 0 f f f f t ...@@ -3915,6 +3915,14 @@ DATA(insert OID = 2515 ( booland_statefunc PGNSP PGUID 12 1 0 0 0 f f f f t
DESCR("aggregate transition function"); DESCR("aggregate transition function");
DATA(insert OID = 2516 ( boolor_statefunc PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "16 16" _null_ _null_ _null_ _null_ boolor_statefunc _null_ _null_ _null_ )); DATA(insert OID = 2516 ( boolor_statefunc PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "16 16" _null_ _null_ _null_ _null_ boolor_statefunc _null_ _null_ _null_ ));
DESCR("aggregate transition function"); DESCR("aggregate transition function");
DATA(insert OID = 3496 ( bool_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 16" _null_ _null_ _null_ _null_ bool_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
DATA(insert OID = 3497 ( bool_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 16" _null_ _null_ _null_ _null_ bool_accum_inv _null_ _null_ _null_ ));
DESCR("aggregate transition function");
DATA(insert OID = 3498 ( bool_alltrue PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 16 "2281" _null_ _null_ _null_ _null_ bool_alltrue _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 3499 ( bool_anytrue PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 16 "2281" _null_ _null_ _null_ _null_ bool_anytrue _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 2517 ( bool_and PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 16 "16" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ )); DATA(insert OID = 2517 ( bool_and PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 16 "16" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("boolean-and aggregate"); DESCR("boolean-and aggregate");
/* ANY, SOME? These names conflict with subquery operators. See doc. */ /* ANY, SOME? These names conflict with subquery operators. See doc. */
......
...@@ -121,6 +121,10 @@ extern Datum boolle(PG_FUNCTION_ARGS); ...@@ -121,6 +121,10 @@ extern Datum boolle(PG_FUNCTION_ARGS);
extern Datum boolge(PG_FUNCTION_ARGS); extern Datum boolge(PG_FUNCTION_ARGS);
extern Datum booland_statefunc(PG_FUNCTION_ARGS); extern Datum booland_statefunc(PG_FUNCTION_ARGS);
extern Datum boolor_statefunc(PG_FUNCTION_ARGS); extern Datum boolor_statefunc(PG_FUNCTION_ARGS);
extern Datum bool_accum(PG_FUNCTION_ARGS);
extern Datum bool_accum_inv(PG_FUNCTION_ARGS);
extern Datum bool_alltrue(PG_FUNCTION_ARGS);
extern Datum bool_anytrue(PG_FUNCTION_ARGS);
extern bool parse_bool(const char *value, bool *result); extern bool parse_bool(const char *value, bool *result);
extern bool parse_bool_with_len(const char *value, size_t len, bool *result); extern bool parse_bool_with_len(const char *value, size_t len, bool *result);
......
...@@ -1769,3 +1769,15 @@ SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FO ...@@ -1769,3 +1769,15 @@ SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FO
1.0 1.0
(2 rows) (2 rows)
SELECT i, b, bool_and(b) OVER w, bool_or(b) OVER w
FROM (VALUES (1,true), (2,true), (3,false), (4,false), (5,true)) v(i,b)
WINDOW w AS (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING);
i | b | bool_and | bool_or
---+---+----------+---------
1 | t | t | t
2 | t | f | t
3 | f | f | f
4 | f | f | t
5 | t | t | t
(5 rows)
...@@ -617,3 +617,7 @@ FROM (VALUES(1,1::numeric),(2,2),(3,'NaN'),(4,3),(5,4)) t(a,b); ...@@ -617,3 +617,7 @@ FROM (VALUES(1,1::numeric),(2,2),(3,'NaN'),(4,3),(5,4)) t(a,b);
-- hard about it. -- hard about it.
SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING),'999999999999999999999D9') SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING),'999999999999999999999D9')
FROM (VALUES(1,1e20),(2,1)) n(i,n); FROM (VALUES(1,1e20),(2,1)) n(i,n);
SELECT i, b, bool_and(b) OVER w, bool_or(b) OVER w
FROM (VALUES (1,true), (2,true), (3,false), (4,false), (5,true)) v(i,b)
WINDOW w AS (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment