-- array hashing with non-hashable element type
SELECT v as value, hash_array(v)::bit(32) as standard
-FROM (VALUES ('{0}'::money[])) x(v);
-ERROR: could not identify a hash function for type money
+FROM (VALUES ('{101}'::varbit[])) x(v);
+ERROR: could not identify a hash function for type bit varying
SELECT v as value, hash_array_extended(v, 0)::bit(32) as extended0
-FROM (VALUES ('{0}'::money[])) x(v);
-ERROR: could not identify an extended hash function for type money
+FROM (VALUES ('{101}'::varbit[])) x(v);
+ERROR: could not identify an extended hash function for type bit varying
SELECT v as value, hashbpchar(v)::bit(32) as standard,
hashbpcharextended(v, 0)::bit(32) as extended0,
hashbpcharextended(v, 1)::bit(32) as extended1
DROP TYPE hash_test_t1;
-- record hashing with non-hashable field type
-CREATE TYPE hash_test_t2 AS (a money, b text);
+CREATE TYPE hash_test_t2 AS (a varbit, b text);
SELECT v as value, hash_record(v)::bit(32) as standard
-FROM (VALUES (row(1, 'aaa')::hash_test_t2)) x(v);
-ERROR: could not identify a hash function for type money
+FROM (VALUES (row('10'::varbit, 'aaa')::hash_test_t2)) x(v);
+ERROR: could not identify a hash function for type bit varying
SELECT v as value, hash_record_extended(v, 0)::bit(32) as extended0
-FROM (VALUES (row(1, 'aaa')::hash_test_t2)) x(v);
-ERROR: could not identify an extended hash function for type money
+FROM (VALUES (row('11'::varbit, 'aaa')::hash_test_t2)) x(v);
+ERROR: could not identify an extended hash function for type bit varying
DROP TYPE hash_test_t2;
--
-- Check special cases for specific data types
-- Check behavior when subtype lacks a hash function
--
set enable_sort = off; -- try to make it pick a hash setop implementation
-select '{(2,5)}'::cashmultirange except select '{(5,6)}'::cashmultirange;
- cashmultirange
------------------
- {($2.00,$5.00)}
+select '{(01,10)}'::varbitmultirange except select '{(10,11)}'::varbitmultirange;
+ varbitmultirange
+------------------
+ {(01,10)}
(1 row)
reset enable_sort;
--
-- Check behavior when subtype lacks a hash function
--
-create type cashrange as range (subtype = money);
+create type varbitrange as range (subtype = varbit);
set enable_sort = off; -- try to make it pick a hash setop implementation
-select '(2,5)'::cashrange except select '(5,6)'::cashrange;
- cashrange
----------------
- ($2.00,$5.00)
+select '(01,10)'::varbitrange except select '(10,11)'::varbitrange;
+ varbitrange
+-------------
+ (01,10)
(1 row)
reset enable_sort;
--
-- Tables and rules for the logging test
--
-create table rtest_emp (ename char(20), salary money);
-create table rtest_emplog (ename char(20), who name, action char(10), newsal money, oldsal money);
-create table rtest_empmass (ename char(20), salary money);
+create table rtest_emp (ename char(20), salary numeric);
+create table rtest_emplog (ename char(20), who name, action char(10), newsal numeric, oldsal numeric);
+create table rtest_empmass (ename char(20), salary numeric);
create rule rtest_emp_ins as on insert to rtest_emp do
insert into rtest_emplog values (new.ename, current_user,
'hired', new.salary, '0.00');
update rtest_emp set salary = '7000.00' where ename = 'wieck';
delete from rtest_emp where ename = 'gates';
select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
- ename | matches user | action | newsal | oldsal
-----------------------+--------------+------------+------------+------------
- gates | t | fired | $0.00 | $80,000.00
- gates | t | hired | $80,000.00 | $0.00
- wiecc | t | hired | $5,000.00 | $0.00
- wieck | t | honored | $6,000.00 | $5,000.00
- wieck | t | honored | $7,000.00 | $6,000.00
+ ename | matches user | action | newsal | oldsal
+----------------------+--------------+------------+----------+----------
+ gates | t | fired | 0.00 | 80000.00
+ gates | t | hired | 80000.00 | 0.00
+ wiecc | t | hired | 5000.00 | 0.00
+ wieck | t | honored | 6000.00 | 5000.00
+ wieck | t | honored | 7000.00 | 6000.00
(5 rows)
insert into rtest_empmass values ('meyer', '4000.00');
insert into rtest_empmass values ('mayr', '6000.00');
insert into rtest_emp select * from rtest_empmass;
select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
- ename | matches user | action | newsal | oldsal
-----------------------+--------------+------------+------------+------------
- gates | t | fired | $0.00 | $80,000.00
- gates | t | hired | $80,000.00 | $0.00
- maier | t | hired | $5,000.00 | $0.00
- mayr | t | hired | $6,000.00 | $0.00
- meyer | t | hired | $4,000.00 | $0.00
- wiecc | t | hired | $5,000.00 | $0.00
- wieck | t | honored | $6,000.00 | $5,000.00
- wieck | t | honored | $7,000.00 | $6,000.00
+ ename | matches user | action | newsal | oldsal
+----------------------+--------------+------------+----------+----------
+ gates | t | fired | 0.00 | 80000.00
+ gates | t | hired | 80000.00 | 0.00
+ maier | t | hired | 5000.00 | 0.00
+ mayr | t | hired | 6000.00 | 0.00
+ meyer | t | hired | 4000.00 | 0.00
+ wiecc | t | hired | 5000.00 | 0.00
+ wieck | t | honored | 6000.00 | 5000.00
+ wieck | t | honored | 7000.00 | 6000.00
(8 rows)
update rtest_empmass set salary = salary + '1000.00';
update rtest_emp set salary = rtest_empmass.salary from rtest_empmass where rtest_emp.ename = rtest_empmass.ename;
select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
- ename | matches user | action | newsal | oldsal
-----------------------+--------------+------------+------------+------------
- gates | t | fired | $0.00 | $80,000.00
- gates | t | hired | $80,000.00 | $0.00
- maier | t | hired | $5,000.00 | $0.00
- maier | t | honored | $6,000.00 | $5,000.00
- mayr | t | hired | $6,000.00 | $0.00
- mayr | t | honored | $7,000.00 | $6,000.00
- meyer | t | hired | $4,000.00 | $0.00
- meyer | t | honored | $5,000.00 | $4,000.00
- wiecc | t | hired | $5,000.00 | $0.00
- wieck | t | honored | $6,000.00 | $5,000.00
- wieck | t | honored | $7,000.00 | $6,000.00
+ ename | matches user | action | newsal | oldsal
+----------------------+--------------+------------+----------+----------
+ gates | t | fired | 0.00 | 80000.00
+ gates | t | hired | 80000.00 | 0.00
+ maier | t | hired | 5000.00 | 0.00
+ maier | t | honored | 6000.00 | 5000.00
+ mayr | t | hired | 6000.00 | 0.00
+ mayr | t | honored | 7000.00 | 6000.00
+ meyer | t | hired | 4000.00 | 0.00
+ meyer | t | honored | 5000.00 | 4000.00
+ wiecc | t | hired | 5000.00 | 0.00
+ wieck | t | honored | 6000.00 | 5000.00
+ wieck | t | honored | 7000.00 | 6000.00
(11 rows)
delete from rtest_emp using rtest_empmass where rtest_emp.ename = rtest_empmass.ename;
select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
- ename | matches user | action | newsal | oldsal
-----------------------+--------------+------------+------------+------------
- gates | t | fired | $0.00 | $80,000.00
- gates | t | hired | $80,000.00 | $0.00
- maier | t | fired | $0.00 | $6,000.00
- maier | t | hired | $5,000.00 | $0.00
- maier | t | honored | $6,000.00 | $5,000.00
- mayr | t | fired | $0.00 | $7,000.00
- mayr | t | hired | $6,000.00 | $0.00
- mayr | t | honored | $7,000.00 | $6,000.00
- meyer | t | fired | $0.00 | $5,000.00
- meyer | t | hired | $4,000.00 | $0.00
- meyer | t | honored | $5,000.00 | $4,000.00
- wiecc | t | hired | $5,000.00 | $0.00
- wieck | t | honored | $6,000.00 | $5,000.00
- wieck | t | honored | $7,000.00 | $6,000.00
+ ename | matches user | action | newsal | oldsal
+----------------------+--------------+------------+----------+----------
+ gates | t | fired | 0.00 | 80000.00
+ gates | t | hired | 80000.00 | 0.00
+ maier | t | fired | 0.00 | 6000.00
+ maier | t | hired | 5000.00 | 0.00
+ maier | t | honored | 6000.00 | 5000.00
+ mayr | t | fired | 0.00 | 7000.00
+ mayr | t | hired | 6000.00 | 0.00
+ mayr | t | honored | 7000.00 | 6000.00
+ meyer | t | fired | 0.00 | 5000.00
+ meyer | t | hired | 4000.00 | 0.00
+ meyer | t | honored | 5000.00 | 4000.00
+ wiecc | t | hired | 5000.00 | 0.00
+ wieck | t | honored | 6000.00 | 5000.00
+ wieck | t | honored | 7000.00 | 6000.00
(14 rows)
--
WITH (autovacuum_enabled = off);
-- over-estimates when using only per-column statistics
INSERT INTO ndistinct (a, b, c, filler1)
- SELECT i/100, i/100, i/100, cash_words((i/100)::money)
+ SELECT i/100, i/100, i/100, (i/100) || ' dollars and zero cents'
FROM generate_series(1,1000) s(i);
ANALYZE ndistinct;
-- Group Aggregate, due to over-estimate of the number of groups
-- under-estimates when using only per-column statistics
INSERT INTO ndistinct (a, b, c, filler1)
SELECT mod(i,13), mod(i,17), mod(i,19),
- cash_words(mod(i,23)::int::money)
+ mod(i,23) || ' dollars and zero cents'
FROM generate_series(1,1000) s(i);
ANALYZE ndistinct;
SELECT s.stxkind, d.stxdndistinct
-- non-hashable type
set enable_hashagg to on;
explain (costs off)
-select x from (values (100::money), (200::money)) _(x) union select x from (values (100::money), (300::money)) _(x);
+select x from (values ('11'::varbit), ('10'::varbit)) _(x) union select x from (values ('11'::varbit), ('10'::varbit)) _(x);
QUERY PLAN
-----------------------------------------------
Unique
set enable_hashagg to off;
explain (costs off)
-select x from (values (100::money), (200::money)) _(x) union select x from (values (100::money), (300::money)) _(x);
+select x from (values ('11'::varbit), ('10'::varbit)) _(x) union select x from (values ('11'::varbit), ('10'::varbit)) _(x);
QUERY PLAN
-----------------------------------------------
Unique
-- non-hashable type
explain (costs off)
-select x from (values (array[100::money]), (array[200::money])) _(x) union select x from (values (array[100::money]), (array[300::money])) _(x);
+select x from (values (array['10'::varbit]), (array['11'::varbit])) _(x) union select x from (values (array['10'::varbit]), (array['01'::varbit])) _(x);
QUERY PLAN
-----------------------------------------------
Unique
-> Values Scan on "*VALUES*_1"
(6 rows)
-select x from (values (array[100::money]), (array[200::money])) _(x) union select x from (values (array[100::money]), (array[300::money])) _(x);
- x
------------
- {$100.00}
- {$200.00}
- {$300.00}
+select x from (values (array['10'::varbit]), (array['11'::varbit])) _(x) union select x from (values (array['10'::varbit]), (array['01'::varbit])) _(x);
+ x
+------
+ {01}
+ {10}
+ {11}
(3 rows)
set enable_hashagg to off;
-- With an anonymous row type, the typcache does not report that the
-- type is hashable. (Otherwise, this would fail at execution time.)
explain (costs off)
-select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
+select x from (values (row('10'::varbit)), (row('11'::varbit))) _(x) union select x from (values (row('10'::varbit)), (row('01'::varbit))) _(x);
QUERY PLAN
-----------------------------------------------
Unique
-> Values Scan on "*VALUES*_1"
(6 rows)
-select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
- x
------------
- ($100.00)
- ($200.00)
- ($300.00)
+select x from (values (row('10'::varbit)), (row('11'::varbit))) _(x) union select x from (values (row('10'::varbit)), (row('01'::varbit))) _(x);
+ x
+------
+ (01)
+ (10)
+ (11)
(3 rows)
-- With a defined row type, the typcache can inspect the type's fields
-- for hashability.
-create type ct1 as (f1 money);
+create type ct1 as (f1 varbit);
explain (costs off)
-select x from (values (row(100::money)::ct1), (row(200::money)::ct1)) _(x) union select x from (values (row(100::money)::ct1), (row(300::money)::ct1)) _(x);
+select x from (values (row('10'::varbit)::ct1), (row('11'::varbit)::ct1)) _(x) union select x from (values (row('10'::varbit)::ct1), (row('01'::varbit)::ct1)) _(x);
QUERY PLAN
-----------------------------------------------
Unique
-> Values Scan on "*VALUES*_1"
(6 rows)
-select x from (values (row(100::money)::ct1), (row(200::money)::ct1)) _(x) union select x from (values (row(100::money)::ct1), (row(300::money)::ct1)) _(x);
- x
------------
- ($100.00)
- ($200.00)
- ($300.00)
+select x from (values (row('10'::varbit)::ct1), (row('11'::varbit)::ct1)) _(x) union select x from (values (row('10'::varbit)::ct1), (row('01'::varbit)::ct1)) _(x);
+ x
+------
+ (01)
+ (10)
+ (11)
(3 rows)
drop type ct1;
-- UNION DISTINCT requires hashable type
WITH RECURSIVE t(n) AS (
- VALUES (1::money)
+ VALUES ('01'::varbit)
UNION
- SELECT n+1::money FROM t WHERE n < 100::money
+ SELECT n || '10'::varbit FROM t WHERE n < '100'::varbit
)
-SELECT sum(n) FROM t;
+SELECT n FROM t;
ERROR: could not implement recursive UNION
DETAIL: All column datatypes must be hashable.
-- recursive view
-- array hashing with non-hashable element type
SELECT v as value, hash_array(v)::bit(32) as standard
-FROM (VALUES ('{0}'::money[])) x(v);
+FROM (VALUES ('{101}'::varbit[])) x(v);
SELECT v as value, hash_array_extended(v, 0)::bit(32) as extended0
-FROM (VALUES ('{0}'::money[])) x(v);
+FROM (VALUES ('{101}'::varbit[])) x(v);
SELECT v as value, hashbpchar(v)::bit(32) as standard,
hashbpcharextended(v, 0)::bit(32) as extended0,
DROP TYPE hash_test_t1;
-- record hashing with non-hashable field type
-CREATE TYPE hash_test_t2 AS (a money, b text);
+CREATE TYPE hash_test_t2 AS (a varbit, b text);
SELECT v as value, hash_record(v)::bit(32) as standard
-FROM (VALUES (row(1, 'aaa')::hash_test_t2)) x(v);
+FROM (VALUES (row('10'::varbit, 'aaa')::hash_test_t2)) x(v);
SELECT v as value, hash_record_extended(v, 0)::bit(32) as extended0
-FROM (VALUES (row(1, 'aaa')::hash_test_t2)) x(v);
+FROM (VALUES (row('11'::varbit, 'aaa')::hash_test_t2)) x(v);
DROP TYPE hash_test_t2;
--
set enable_sort = off; -- try to make it pick a hash setop implementation
-select '{(2,5)}'::cashmultirange except select '{(5,6)}'::cashmultirange;
+select '{(01,10)}'::varbitmultirange except select '{(10,11)}'::varbitmultirange;
reset enable_sort;
-- Check behavior when subtype lacks a hash function
--
-create type cashrange as range (subtype = money);
+create type varbitrange as range (subtype = varbit);
set enable_sort = off; -- try to make it pick a hash setop implementation
-select '(2,5)'::cashrange except select '(5,6)'::cashrange;
+select '(01,10)'::varbitrange except select '(10,11)'::varbitrange;
reset enable_sort;
--
-- Tables and rules for the logging test
--
-create table rtest_emp (ename char(20), salary money);
-create table rtest_emplog (ename char(20), who name, action char(10), newsal money, oldsal money);
-create table rtest_empmass (ename char(20), salary money);
+create table rtest_emp (ename char(20), salary numeric);
+create table rtest_emplog (ename char(20), who name, action char(10), newsal numeric, oldsal numeric);
+create table rtest_empmass (ename char(20), salary numeric);
create rule rtest_emp_ins as on insert to rtest_emp do
insert into rtest_emplog values (new.ename, current_user,
-- over-estimates when using only per-column statistics
INSERT INTO ndistinct (a, b, c, filler1)
- SELECT i/100, i/100, i/100, cash_words((i/100)::money)
+ SELECT i/100, i/100, i/100, (i/100) || ' dollars and zero cents'
FROM generate_series(1,1000) s(i);
ANALYZE ndistinct;
-- under-estimates when using only per-column statistics
INSERT INTO ndistinct (a, b, c, filler1)
SELECT mod(i,13), mod(i,17), mod(i,19),
- cash_words(mod(i,23)::int::money)
+ mod(i,23) || ' dollars and zero cents'
FROM generate_series(1,1000) s(i);
ANALYZE ndistinct;
set enable_hashagg to on;
explain (costs off)
-select x from (values (100::money), (200::money)) _(x) union select x from (values (100::money), (300::money)) _(x);
+select x from (values ('11'::varbit), ('10'::varbit)) _(x) union select x from (values ('11'::varbit), ('10'::varbit)) _(x);
set enable_hashagg to off;
explain (costs off)
-select x from (values (100::money), (200::money)) _(x) union select x from (values (100::money), (300::money)) _(x);
+select x from (values ('11'::varbit), ('10'::varbit)) _(x) union select x from (values ('11'::varbit), ('10'::varbit)) _(x);
reset enable_hashagg;
-- non-hashable type
explain (costs off)
-select x from (values (array[100::money]), (array[200::money])) _(x) union select x from (values (array[100::money]), (array[300::money])) _(x);
-select x from (values (array[100::money]), (array[200::money])) _(x) union select x from (values (array[100::money]), (array[300::money])) _(x);
+select x from (values (array['10'::varbit]), (array['11'::varbit])) _(x) union select x from (values (array['10'::varbit]), (array['01'::varbit])) _(x);
+select x from (values (array['10'::varbit]), (array['11'::varbit])) _(x) union select x from (values (array['10'::varbit]), (array['01'::varbit])) _(x);
set enable_hashagg to off;
-- With an anonymous row type, the typcache does not report that the
-- type is hashable. (Otherwise, this would fail at execution time.)
explain (costs off)
-select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
-select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
+select x from (values (row('10'::varbit)), (row('11'::varbit))) _(x) union select x from (values (row('10'::varbit)), (row('01'::varbit))) _(x);
+select x from (values (row('10'::varbit)), (row('11'::varbit))) _(x) union select x from (values (row('10'::varbit)), (row('01'::varbit))) _(x);
-- With a defined row type, the typcache can inspect the type's fields
-- for hashability.
-create type ct1 as (f1 money);
+create type ct1 as (f1 varbit);
explain (costs off)
-select x from (values (row(100::money)::ct1), (row(200::money)::ct1)) _(x) union select x from (values (row(100::money)::ct1), (row(300::money)::ct1)) _(x);
-select x from (values (row(100::money)::ct1), (row(200::money)::ct1)) _(x) union select x from (values (row(100::money)::ct1), (row(300::money)::ct1)) _(x);
+select x from (values (row('10'::varbit)::ct1), (row('11'::varbit)::ct1)) _(x) union select x from (values (row('10'::varbit)::ct1), (row('01'::varbit)::ct1)) _(x);
+select x from (values (row('10'::varbit)::ct1), (row('11'::varbit)::ct1)) _(x) union select x from (values (row('10'::varbit)::ct1), (row('01'::varbit)::ct1)) _(x);
drop type ct1;
set enable_hashagg to off;
-- UNION DISTINCT requires hashable type
WITH RECURSIVE t(n) AS (
- VALUES (1::money)
+ VALUES ('01'::varbit)
UNION
- SELECT n+1::money FROM t WHERE n < 100::money
+ SELECT n || '10'::varbit FROM t WHERE n < '100'::varbit
)
-SELECT sum(n) FROM t;
+SELECT n FROM t;
-- recursive view
CREATE RECURSIVE VIEW nums (n) AS