index 41d540b46ecded139d59d6290ef53b9df2660f0d..7b25947682e80341e52dd6aec126de5340967fc0 100644 (file)
#include <math.h>
#include <limits.h>
+#include "access/hash.h"
#include "access/heapam.h"
#include "access/sysattr.h"
#include "catalog/namespace.h"
PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
}
+Datum
+hashtid(PG_FUNCTION_ARGS)
+{
+ ItemPointer key = PG_GETARG_ITEMPOINTER(0);
+
+ /*
+ * While you'll probably have a lot of trouble with a compiler that
+ * insists on appending pad space to struct ItemPointerData, we can at
+ * least make this code work, by not using sizeof(ItemPointerData).
+ * Instead rely on knowing the sizes of the component fields.
+ */
+ return hash_any((unsigned char *) key,
+ sizeof(BlockIdData) + sizeof(OffsetNumber));
+}
+
+Datum
+hashtidextended(PG_FUNCTION_ARGS)
+{
+ ItemPointer key = PG_GETARG_ITEMPOINTER(0);
+ uint64 seed = PG_GETARG_INT64(1);
+
+ /* As above */
+ return hash_any_extended((unsigned char *) key,
+ sizeof(BlockIdData) + sizeof(OffsetNumber),
+ seed);
+}
+
/*
* Functions to get latest tid of a specified tuple.
index 0e89b303650bf2eb94d999d5a31ea77281b2d73e..588a110093a6d85569462f059a7ba0ddd6f633a8 100644 (file)
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201812202
+#define CATALOG_VERSION_NO 201812301
#endif
index e689c9b160ae4898eba7b0210b06d435196720fd..436f1bd0762ddabd31b0c9d950c8e917b13112c7 100644 (file)
{ amopfamily => 'hash/cid_ops', amoplefttype => 'cid', amoprighttype => 'cid',
amopstrategy => '1', amopopr => '=(cid,cid)', amopmethod => 'hash' },
+# tid_ops
+{ amopfamily => 'hash/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid',
+ amopstrategy => '1', amopopr => '=(tid,tid)', amopmethod => 'hash' },
+
# text_pattern_ops
{ amopfamily => 'hash/text_pattern_ops', amoplefttype => 'text',
amoprighttype => 'text', amopstrategy => '1', amopopr => '=(text,text)',
index bbcee26fa8b6929868df5d2ca8775135860e0d63..8ddb6991121a0e1662f0d8eef66c8d3a1dcd887f 100644 (file)
amprocrighttype => 'cid', amprocnum => '1', amproc => 'hashint4' },
{ amprocfamily => 'hash/cid_ops', amproclefttype => 'cid',
amprocrighttype => 'cid', amprocnum => '2', amproc => 'hashint4extended' },
+{ amprocfamily => 'hash/tid_ops', amproclefttype => 'tid',
+ amprocrighttype => 'tid', amprocnum => '1', amproc => 'hashtid' },
+{ amprocfamily => 'hash/tid_ops', amproclefttype => 'tid',
+ amprocrighttype => 'tid', amprocnum => '2', amproc => 'hashtidextended' },
{ amprocfamily => 'hash/text_pattern_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '1', amproc => 'hashtext' },
{ amprocfamily => 'hash/text_pattern_ops', amproclefttype => 'text',
index 5178d04337fa8ebab007cd7acb1d45e675ae9c58..c451d365a6f7e820d5055a1a8cc8c8bde0a3a513 100644 (file)
opcintype => 'xid' },
{ opcmethod => 'hash', opcname => 'cid_ops', opcfamily => 'hash/cid_ops',
opcintype => 'cid' },
+{ opcmethod => 'hash', opcname => 'tid_ops', opcfamily => 'hash/tid_ops',
+ opcintype => 'tid' },
{ opcmethod => 'hash', opcname => 'text_pattern_ops',
opcfamily => 'hash/text_pattern_ops', opcintype => 'text',
opcdefault => 'f' },
index 2abd5311c3e5b59b25f329f3250da37413e6b446..e8452e10d21bb2782655786eb4ac4ca90b2537f6 100644 (file)
oprrest => 'eqsel', oprjoin => 'eqjoinsel' },
{ oid => '387', oid_symbol => 'TIDEqualOperator', descr => 'equal',
- oprname => '=', oprcanmerge => 't', oprleft => 'tid', oprright => 'tid',
- oprresult => 'bool', oprcom => '=(tid,tid)', oprnegate => '<>(tid,tid)',
- oprcode => 'tideq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' },
+ oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'tid',
+ oprright => 'tid', oprresult => 'bool', oprcom => '=(tid,tid)',
+ oprnegate => '<>(tid,tid)', oprcode => 'tideq', oprrest => 'eqsel',
+ oprjoin => 'eqjoinsel' },
{ oid => '402', descr => 'not equal',
oprname => '<>', oprleft => 'tid', oprright => 'tid', oprresult => 'bool',
oprcom => '<>(tid,tid)', oprnegate => '=(tid,tid)', oprcode => 'tidne',
index fe8a32485f2742c36293562363115f4363cb1de9..c5ea37b5cd759e0a85ae2544ff4b18d894d3cb91 100644 (file)
opfmethod => 'hash', opfname => 'xid_ops' },
{ oid => '2226',
opfmethod => 'hash', opfname => 'cid_ops' },
+{ oid => '2227',
+ opfmethod => 'hash', opfname => 'tid_ops' },
{ oid => '2229',
opfmethod => 'hash', opfname => 'text_pattern_ops' },
{ oid => '2231',
index acb0154048a0f0740b6a1eb8c5dfec4ecf11f5e2..6e1e1dfad71c64e55de4a52fe12537a9548d8eeb 100644 (file)
{ oid => '2796', descr => 'smaller of two',
proname => 'tidsmaller', prorettype => 'tid', proargtypes => 'tid tid',
prosrc => 'tidsmaller' },
+{ oid => '2233', descr => 'hash',
+ proname => 'hashtid', prorettype => 'int4', proargtypes => 'tid',
+ prosrc => 'hashtid' },
+{ oid => '2234', descr => 'hash',
+ proname => 'hashtidextended', prorettype => 'int8', proargtypes => 'tid int8',
+ prosrc => 'hashtidextended' },
{ oid => '1296',
proname => 'timedate_pl', prolang => '14', prorettype => 'timestamp',
index 8f15c04dad1aafa4ebeaa8f44886b44db0704d1a..9b5eb04bfd9c11a038c12d7fe72dbdf0b6d0e46c 100644 (file)
@@ -109,6 +109,7 @@ WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
(2 rows)
-- nestloop-with-inner-tidscan joins on tid
+SET enable_hashjoin TO off; -- otherwise hash join might win
EXPLAIN (COSTS OFF)
SELECT t1.ctid, t1.*, t2.ctid, t2.*
FROM tidscan t1 JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
@@ -147,6 +148,7 @@ FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
(0,1) | 1 | (0,1) | 1
(1 row)
+RESET enable_hashjoin;
-- exercise backward scan and rewind
BEGIN;
DECLARE c CURSOR FOR
@@ -231,4 +233,48 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
ERROR: cursor "c" is not positioned on a row
ROLLBACK;
+-- bulk joins on CTID
+-- (these plans don't use TID scans, but this still seems like an
+-- appropriate place for these tests)
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Join
+ Hash Cond: (t1.ctid = t2.ctid)
+ -> Seq Scan on tenk1 t1
+ -> Hash
+ -> Seq Scan on tenk1 t2
+(6 rows)
+
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+ count
+-------
+ 10000
+(1 row)
+
+SET enable_hashjoin TO off;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+ QUERY PLAN
+-----------------------------------------
+ Aggregate
+ -> Merge Join
+ Merge Cond: (t1.ctid = t2.ctid)
+ -> Sort
+ Sort Key: t1.ctid
+ -> Seq Scan on tenk1 t1
+ -> Sort
+ Sort Key: t2.ctid
+ -> Seq Scan on tenk1 t2
+(9 rows)
+
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+ count
+-------
+ 10000
+(1 row)
+
+RESET enable_hashjoin;
DROP TABLE tidscan;
index 2d63aa067fef88a9ef552a94123c2f7e06952a63..ef05c0984207919626a14d9ab5581f76d73bca8c 100644 (file)
WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
-- nestloop-with-inner-tidscan joins on tid
+SET enable_hashjoin TO off; -- otherwise hash join might win
EXPLAIN (COSTS OFF)
SELECT t1.ctid, t1.*, t2.ctid, t2.*
FROM tidscan t1 JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
@@ -50,6 +51,7 @@ SELECT t1.ctid, t1.*, t2.ctid, t2.*
FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
SELECT t1.ctid, t1.*, t2.ctid, t2.*
FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
+RESET enable_hashjoin;
-- exercise backward scan and rewind
BEGIN;
@@ -80,4 +82,16 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
ROLLBACK;
+-- bulk joins on CTID
+-- (these plans don't use TID scans, but this still seems like an
+-- appropriate place for these tests)
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+SET enable_hashjoin TO off;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
+RESET enable_hashjoin;
+
DROP TABLE tidscan;