diff options
-rw-r--r-- | src/backend/utils/adt/bool.c | 109 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_aggregate.h | 6 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 8 | ||||
-rw-r--r-- | src/include/utils/builtins.h | 4 | ||||
-rw-r--r-- | src/test/regress/expected/window.out | 12 | ||||
-rw-r--r-- | src/test/regress/sql/window.sql | 4 |
7 files changed, 137 insertions, 8 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); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 0d301cf1ace..74c6bff86d7 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201404122 +#define CATALOG_VERSION_NO 201404123 #endif diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 5116beb62a9..89a56d5b8e2 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -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_ )); /* boolean-and and boolean-or */ -DATA(insert ( 2517 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); -DATA(insert ( 2518 n 0 boolor_statefunc - - - - 59 16 0 0 0 _null_ _null_ )); -DATA(insert ( 2519 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 - bool_accum bool_accum_inv bool_anytrue 59 16 0 2281 16 _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 */ DATA(insert ( 2236 n 0 int2and - - - - 0 21 0 0 0 _null_ _null_ )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index a24f4e02f96..643408d250c 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -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"); 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"); +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_ )); DESCR("boolean-and aggregate"); /* ANY, SOME? These names conflict with subquery operators. See doc. */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index f7cc1af2caf..11ff4fdef0c 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -121,6 +121,10 @@ extern Datum boolle(PG_FUNCTION_ARGS); extern Datum boolge(PG_FUNCTION_ARGS); extern Datum booland_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_with_len(const char *value, size_t len, bool *result); diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index f08bd9c9adc..c2cc742c903 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -1769,3 +1769,15 @@ SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FO 1.0 (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) + diff --git a/src/test/regress/sql/window.sql b/src/test/regress/sql/window.sql index 11c96aa8bc0..31c98eb2705 100644 --- a/src/test/regress/sql/window.sql +++ b/src/test/regress/sql/window.sql @@ -617,3 +617,7 @@ FROM (VALUES(1,1::numeric),(2,2),(3,'NaN'),(4,3),(5,4)) t(a,b); -- hard about it. 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); + +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); |