*** ./doc/src/sgml/func.sgml.orig Mon Apr 26 14:00:58 2004 --- ./doc/src/sgml/func.sgml Sat May 1 15:49:39 2004 *************** *** 7544,7549 **** --- 7544,7617 ---- + + + bit_and + + bit_and(expression) + + + smallint, integer, bigint or + bit, + + + same as argument data type. + + the bitwise-and all non-null input values, or null if empty + + + + + + + bit_or + + bit_or(expression) + + + smallint, integer, bigint or + bit, + + + same as argument data type. + + the bitwise-or all non-null input values, or null if empty + + + + + + + bool_and + + bool_and(expression) + + + bool + + + bool + + true if all input values are true, otherwise false + + + + + + bool_or + + bool_or(expression) + + + bool + + + bool + + true if at least one input value is true, otherwise false + + + count(*) bigint *************** *** 7644,7649 **** --- 7712,7718 ---- It should be noted that except for count, + bool_and and bool_or, these functions return a null value when no rows are selected. In particular, sum of no rows returns null, not zero as one might expect. The function coalesce may be *** ./src/backend/utils/adt/bool.c.orig Sat Nov 29 20:51:58 2003 --- ./src/backend/utils/adt/bool.c Sat May 1 16:02:30 2004 *************** *** 248,250 **** --- 248,325 ---- PG_RETURN_BOOL(b); } + + /* + * boolean-and and boolean-or aggregates. + * + * this correspond to EVERY and ANY/SOME aggregate in SQL-2003. + * There is an ambiguity in the syntax shown by Tom: + * SELECT b1 = ANY((SELECT b2 FROM t2)) FROM t1; + * can be interpreted as either an aggregate or as an any sub-select. + * + * About the semantics: as per the sql standard, these aggregates + * must return either true or false, but not null, even on empty input. + */ + + /* EVERY aggregate implementation conforming to SQL 2003 standard. + * must be non strict. no special assumption about state and data. + */ + PG_FUNCTION_INFO_V1(booland_statefunc); + + Datum booland_statefunc(PG_FUNCTION_ARGS) + { + bool state, data; + + /* get data item. if in doubt (NULL boolean), EVERY is false. */ + if (PG_ARGISNULL(1)) + PG_RETURN_BOOL(false); + data = PG_GETARG_BOOL(1); + + /* get internal state */ + if (PG_ARGISNULL(0)) + PG_RETURN_BOOL(data); /* initialization with supplied non-null data */ + state = PG_GETARG_BOOL(0); + + PG_RETURN_BOOL(state && data); + } + + /* SOME aggregate implementation conforming to SQL 2003 standard. + * must be non strict. no special assumption about state and data. + */ + PG_FUNCTION_INFO_V1(boolor_statefunc); + + Datum boolor_statefunc(PG_FUNCTION_ARGS) + { + bool state, data, nullstate, nulldata; + + nullstate = PG_ARGISNULL(0); + nulldata = PG_ARGISNULL(1); + + if (nullstate) + { + if (nulldata) + PG_RETURN_NULL(); + else + PG_RETURN_BOOL(PG_GETARG_BOOL(1)); /* set initial state */ + } + /* else !nullstate */ + state = PG_GETARG_BOOL(0); + if (nulldata) + PG_RETURN_BOOL(state); /* state is not changed */ + + data = PG_GETARG_BOOL(1); + PG_RETURN_BOOL(state || data); + } + + /* used both by EVERY and SOME */ + PG_FUNCTION_INFO_V1(state_or_false_finalfunc); + + Datum state_or_false_finalfunc(PG_FUNCTION_ARGS) + { + /* if in doubt (empty set), returns false */ + if (PG_ARGISNULL(0)) + PG_RETURN_BOOL(false); + + /* returns internal state */ + PG_RETURN_BOOL(PG_GETARG_BOOL(0)); + } *** ./src/include/catalog/catversion.h.orig Mon Apr 26 18:50:08 2004 --- ./src/include/catalog/catversion.h Sat May 1 12:53:35 2004 *************** *** 53,58 **** */ /* yyyymmddN */ ! #define CATALOG_VERSION_NO 200404260 #endif --- 53,58 ---- */ /* yyyymmddN */ ! #define CATALOG_VERSION_NO 200405010 #endif *** ./src/include/catalog/pg_aggregate.h.orig Sat Nov 29 23:40:58 2003 --- ./src/include/catalog/pg_aggregate.h Sat May 1 13:44:01 2004 *************** *** 149,154 **** --- 149,168 ---- DATA(insert ( 2158 float8_accum float8_stddev 1022 "{0,0,0}" )); DATA(insert ( 2159 numeric_accum numeric_stddev 1231 "{0,0,0}" )); + /* boolean-and and boolean-or */ + DATA(insert ( 2518 booland_statefunc state_or_false_finalfunc 16 _null_ )); + DATA(insert ( 2519 boolor_statefunc state_or_false_finalfunc 16 _null_ )); + + /* bitwise integer */ + DATA(insert ( 2535 int2and - 21 _null_ )); + DATA(insert ( 2536 int2or - 21 _null_ )); + DATA(insert ( 2537 int4and - 23 _null_ )); + DATA(insert ( 2538 int4or - 23 _null_ )); + DATA(insert ( 2539 int8and - 20 _null_ )); + DATA(insert ( 2540 int8or - 20 _null_ )); + DATA(insert ( 2541 bitand - 1560 _null_ )); + DATA(insert ( 2542 bitor - 1560 _null_ )); + /* * prototypes for functions in pg_aggregate.c */ *** ./src/include/catalog/pg_proc.h.orig Mon Apr 26 18:50:10 2004 --- ./src/include/catalog/pg_proc.h Sat May 1 13:50:24 2004 *************** *** 3546,3551 **** --- 3546,3585 ---- DATA(insert OID = 2514 ( aclitem_goptions PGNSP PGUID 12 f f t f i 1 23 "1033" _null_ aclitem_goptions - _null_ )); DESCR("extract grant options from aclitem"); + /* boolean aggregates */ + DATA(insert OID = 2515 ( booland_statefunc PGNSP PGUID 12 f f f f i 2 16 "16 16" _null_ booland_statefunc - _null_ )); + DESCR("boolean-and aggregate transition function"); + DATA(insert OID = 2516 ( boolor_statefunc PGNSP PGUID 12 f f f f i 2 16 "16 16" _null_ boolor_statefunc - _null_ )); + DESCR("boolean-or aggregate transition function"); + DATA(insert OID = 2517 ( state_or_false_finalfunc PGNSP PGUID 12 f f f f i 1 16 "16" _null_ state_or_false_finalfunc - _null_ )); + DESCR("boolean-and and boolean-or aggregate final function"); + /* what about every? */ + DATA(insert OID = 2518 ( bool_and PGNSP PGUID 12 t f f f i 1 16 "16" _null_ aggregate_dummy - _null_ )); + DESCR("boolean-and aggregate"); + /* what about any/some? */ + DATA(insert OID = 2519 ( bool_or PGNSP PGUID 12 t f f f i 1 16 "16" _null_ aggregate_dummy - _null_ )); + DESCR("boolean-or aggregate"); + + /* bitwise integer aggregates */ + DATA(insert OID = 2535 ( bit_and PGNSP PGUID 12 t f f f i 1 21 "21" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-and smallint aggregate"); + DATA(insert OID = 2536 ( bit_or PGNSP PGUID 12 t f f f i 1 21 "21" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-or smallint aggregate"); + + DATA(insert OID = 2537 ( bit_and PGNSP PGUID 12 t f f f i 1 23 "23" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-and integer aggregate"); + DATA(insert OID = 2538 ( bit_or PGNSP PGUID 12 t f f f i 1 23 "23" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-or integer aggregate"); + + DATA(insert OID = 2539 ( bit_and PGNSP PGUID 12 t f f f i 1 20 "20" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-and bigint aggregate"); + DATA(insert OID = 2540 ( bit_or PGNSP PGUID 12 t f f f i 1 20 "20" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-or bigint aggregate"); + + DATA(insert OID = 2541 ( bit_and PGNSP PGUID 12 t f f f i 1 1560 "1560" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-and bit aggregate"); + DATA(insert OID = 2542 ( bit_or PGNSP PGUID 12 t f f f i 1 1560 "1560" _null_ aggregate_dummy - _null_)); + DESCR("bitwise-or bit aggregate"); /* * Symbolic values for provolatile column: these indicate whether the result *** ./src/include/utils/builtins.h.orig Mon Apr 5 12:06:43 2004 --- ./src/include/utils/builtins.h Sat May 1 12:21:13 2004 *************** *** 68,73 **** --- 68,76 ---- extern Datum isfalse(PG_FUNCTION_ARGS); extern Datum isnottrue(PG_FUNCTION_ARGS); extern Datum isnotfalse(PG_FUNCTION_ARGS); + extern Datum booland_statefunc(PG_FUNCTION_ARGS); + extern Datum boolor_statefunc(PG_FUNCTION_ARGS); + extern Datum state_or_false_finalfunc(PG_FUNCTION_ARGS); /* char.c */ extern Datum charin(PG_FUNCTION_ARGS); *** ./src/test/regress/expected/aggregates.out.orig Sat Jul 19 22:20:52 2003 --- ./src/test/regress/expected/aggregates.out Sat May 1 15:58:50 2004 *************** *** 157,159 **** --- 157,266 ---- having exists (select 1 from onek b where sum(distinct a.four + b.four) = b.four); ERROR: aggregates not allowed in WHERE clause + -- + -- test for bitwise integer aggregates + -- + CREATE TEMPORARY TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2, + y BIT(4) + ); + -- empty case + SELECT + BIT_AND(i2) AS "?", + BIT_OR(i4) AS "?" + FROM bitwise_test; + ? | ? + ---+--- + | + (1 row) + + COPY bitwise_test FROM STDIN NULL 'null'; + SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_AND(y) AS "0100", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7", + BIT_OR(y) AS "1101" + FROM bitwise_test; + 1 | 1 | 1 | ? | 0 | 0100 | 7 | 7 | 7 | ? | 7 | 1101 + ---+---+---+---+---+------+---+---+---+---+---+------ + 1 | 1 | 1 | 1 | 0 | 0100 | 7 | 7 | 7 | 3 | 7 | 1101 + (1 row) + + -- + -- test boolean aggregates + -- + -- first test all possible transition and final states + SELECT + -- boolean and transitions + NOT booland_statefunc(NULL, NULL) + AND booland_statefunc(NULL, TRUE) + AND NOT booland_statefunc(NULL, FALSE) + AND NOT booland_statefunc(TRUE, NULL) + AND booland_statefunc(TRUE, TRUE) + AND NOT booland_statefunc(TRUE, FALSE) + AND NOT booland_statefunc(FALSE, NULL) + AND NOT booland_statefunc(FALSE, TRUE) + AND NOT booland_statefunc(FALSE, FALSE) AS "booland", + -- boolean or transitions + boolor_statefunc(NULL, NULL) IS NULL -- could also be FALSE + AND boolor_statefunc(NULL, TRUE) + AND NOT boolor_statefunc(NULL, FALSE) + AND boolor_statefunc(TRUE, NULL) + AND boolor_statefunc(TRUE, TRUE) + AND boolor_statefunc(TRUE, FALSE) + AND NOT boolor_statefunc(FALSE, NULL) + AND boolor_statefunc(FALSE, TRUE) + AND NOT boolor_statefunc(FALSE, FALSE) AS "boolor", + + -- final function + NOT state_or_false_finalfunc(NULL) + AND NOT state_or_false_finalfunc(FALSE) + AND state_or_false_finalfunc(TRUE) AS "final" + ; + booland | boolor | final + ---------+--------+------- + t | t | t + (1 row) + + CREATE TEMPORARY TABLE bool_test( + b1 BOOL, + b2 BOOL, + b3 BOOL); + -- empty case + SELECT + BOOL_AND(b1) AS "f", + BOOL_OR(b3) AS "f" + FROM bool_test; + f | f + ---+--- + f | f + (1 row) + + COPY bool_test FROM STDIN NULL 'null'; + SELECT + BOOL_AND(b1) AS "f", + BOOL_AND(b2) AS "t", + BOOL_AND(b3) AS "f", + BOOL_AND(NOT b2) AS "f", + BOOL_OR(b1) AS "t", + BOOL_OR(b2) AS "t", + BOOL_OR(b3) AS "f", + BOOL_OR(NOT b2) AS "f" + FROM bool_test; + f | t | f | f | t | t | f | f + ---+---+---+---+---+---+---+--- + f | t | f | f | t | t | f | f + (1 row) + *** ./src/test/regress/sql/aggregates.sql.orig Fri Jun 6 17:04:03 2003 --- ./src/test/regress/sql/aggregates.sql Sat May 1 15:57:20 2004 *************** *** 62,64 **** --- 62,166 ---- group by ten having exists (select 1 from onek b where sum(distinct a.four + b.four) = b.four); + + -- + -- test for bitwise integer aggregates + -- + CREATE TEMPORARY TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2, + y BIT(4) + ); + + -- empty case + SELECT + BIT_AND(i2) AS "?", + BIT_OR(i4) AS "?" + FROM bitwise_test; + + COPY bitwise_test FROM STDIN NULL 'null'; + 1 1 1 1 1 B0101 + 3 3 3 null 2 B0100 + 7 7 7 3 4 B1100 + \. + + SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_AND(y) AS "0100", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7", + BIT_OR(y) AS "1101" + FROM bitwise_test; + + -- + -- test boolean aggregates + -- + -- first test all possible transition and final states + SELECT + -- boolean and transitions + NOT booland_statefunc(NULL, NULL) + AND booland_statefunc(NULL, TRUE) + AND NOT booland_statefunc(NULL, FALSE) + AND NOT booland_statefunc(TRUE, NULL) + AND booland_statefunc(TRUE, TRUE) + AND NOT booland_statefunc(TRUE, FALSE) + AND NOT booland_statefunc(FALSE, NULL) + AND NOT booland_statefunc(FALSE, TRUE) + AND NOT booland_statefunc(FALSE, FALSE) AS "booland", + + -- boolean or transitions + boolor_statefunc(NULL, NULL) IS NULL -- could also be FALSE + AND boolor_statefunc(NULL, TRUE) + AND NOT boolor_statefunc(NULL, FALSE) + AND boolor_statefunc(TRUE, NULL) + AND boolor_statefunc(TRUE, TRUE) + AND boolor_statefunc(TRUE, FALSE) + AND NOT boolor_statefunc(FALSE, NULL) + AND boolor_statefunc(FALSE, TRUE) + AND NOT boolor_statefunc(FALSE, FALSE) AS "boolor", + + -- final function + NOT state_or_false_finalfunc(NULL) + AND NOT state_or_false_finalfunc(FALSE) + AND state_or_false_finalfunc(TRUE) AS "final" + ; + + CREATE TEMPORARY TABLE bool_test( + b1 BOOL, + b2 BOOL, + b3 BOOL); + + -- empty case + SELECT + BOOL_AND(b1) AS "f", + BOOL_OR(b3) AS "f" + FROM bool_test; + + COPY bool_test FROM STDIN NULL 'null'; + TRUE TRUE FALSE + FALSE TRUE null + null TRUE FALSE + \. + + SELECT + BOOL_AND(b1) AS "f", + BOOL_AND(b2) AS "t", + BOOL_AND(b3) AS "f", + BOOL_AND(NOT b2) AS "f", + + BOOL_OR(b1) AS "t", + BOOL_OR(b2) AS "t", + BOOL_OR(b3) AS "f", + BOOL_OR(NOT b2) AS "f" + FROM bool_test;