aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/bool.c109
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_aggregate.h6
-rw-r--r--src/include/catalog/pg_proc.h8
-rw-r--r--src/include/utils/builtins.h4
-rw-r--r--src/test/regress/expected/window.out12
-rw-r--r--src/test/regress/sql/window.sql4
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);