sort-support.patch
application/octet-stream
Filename: sort-support.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| doc/src/sgml/xindex.sgml | 2 | 1 |
| src/backend/access/nbtree/nbtcompare.c | 23 | 0 |
| src/include/access/nbtree.h | 9 | 5 |
| src/include/catalog/pg_am.h | 1 | 1 |
| src/include/catalog/pg_amproc.h | 1 | 0 |
| src/include/catalog/pg_proc.h | 2 | 0 |
| src/include/utils/builtins.h | 7 | 0 |
| src/include/utils/sortsupport.h | 43 | 0 |
| src/test/regress/expected/opr_sanity.out | 19 | 30 |
| src/test/regress/sql/opr_sanity.sql | 19 | 28 |
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
index 2832436..5f67624 100644
--- a/doc/src/sgml/xindex.sgml
+++ b/doc/src/sgml/xindex.sgml
@@ -758,7 +758,8 @@ DEFAULT FOR TYPE int4 USING btree FAMILY integer_ops AS
OPERATOR 3 = ,
OPERATOR 4 >= ,
OPERATOR 5 > ,
- FUNCTION 1 btint4cmp(int4, int4) ;
+ FUNCTION 1 btint4cmp(int4, int4),
+ FUNCTION 2 btint4sortsupport(int4, int4) ;
CREATE OPERATOR CLASS int2_ops
DEFAULT FOR TYPE int2 USING btree FAMILY integer_ops AS
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index 23f2b61..f95bc9f 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -49,6 +49,7 @@
#include "postgres.h"
#include "utils/builtins.h"
+#include "utils/sortsupport.h"
Datum
@@ -83,6 +84,28 @@ btint4cmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(-1);
}
+static int
+btint4acmp(Datum a, Datum b, SortSupportInfo ss)
+{
+ int32 a1 = Int32GetDatum(a);
+ int32 b1 = Int32GetDatum(b);
+
+ if (a1 > b1)
+ return 1;
+ else if (a1 == b1)
+ return 0;
+ else
+ return -1;
+}
+
+Datum
+btint4sortsupport(PG_FUNCTION_ARGS)
+{
+ SortSupportInfo ss = (SortSupportInfo) PG_GETARG_POINTER(0);
+ ss->extra = btint4acmp;
+ PG_RETURN_VOID();
+}
+
Datum
btint8cmp(PG_FUNCTION_ARGS)
{
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 347d942..b17855e 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -417,13 +417,17 @@ typedef struct xl_btree_newroot
/*
* When a new operator class is declared, we require that the user
- * supply us with an amproc procedure for determining whether, for
- * two keys a and b, a < b, a = b, or a > b. This routine must
- * return < 0, 0, > 0, respectively, in these three cases. Since we
- * only have one such proc in amproc, it's number 1.
+ * supply us with an amproc procedure (BTORDER_PROC) for determining
+ * whether, for two keys a and b, a < b, a = b, or a > b. This routine
+ * must return < 0, 0, > 0, respectively, in these three cases.
+ *
+ * To facilitate accelerated sorting, an operator class may choose to
+ * offer a second procedure (BTSORTSUPPORT_PROC). For full details, see
+ * src/include/utils/sortsupport.h
*/
-#define BTORDER_PROC 1
+#define BTORDER_PROC 1
+#define BTSORTSUPPORT_PROC 2
/*
* We need to be able to tell the difference between read and write
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 8b075d3..ddacdf2 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -117,7 +117,7 @@ typedef FormData_pg_am *Form_pg_am;
* ----------------
*/
-DATA(insert OID = 403 ( btree 5 1 t f t t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcostestimate btoptions ));
+DATA(insert OID = 403 ( btree 5 2 t f t t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index e5d43f7..373191a 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -100,6 +100,7 @@ DATA(insert ( 1976 21 21 1 350 ));
DATA(insert ( 1976 21 23 1 2190 ));
DATA(insert ( 1976 21 20 1 2192 ));
DATA(insert ( 1976 23 23 1 351 ));
+DATA(insert ( 1976 23 23 2 324 ));
DATA(insert ( 1976 23 20 1 2188 ));
DATA(insert ( 1976 23 21 1 2191 ));
DATA(insert ( 1976 20 20 1 842 ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 28e53b7..e062b80 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -568,6 +568,8 @@ DATA(insert OID = 350 ( btint2cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23
DESCR("less-equal-greater");
DATA(insert OID = 351 ( btint4cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "23 23" _null_ _null_ _null_ _null_ btint4cmp _null_ _null_ _null_ ));
DESCR("less-equal-greater");
+DATA(insert OID = 324 ( btint4sortsupport PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2278 "2281" _null_ _null_ _null_ _null_ btint4sortsupport _null_ _null_ _null_ ));
+DESCR("sort support");
DATA(insert OID = 842 ( btint8cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "20 20" _null_ _null_ _null_ _null_ btint8cmp _null_ _null_ _null_ ));
DESCR("less-equal-greater");
DATA(insert OID = 354 ( btfloat4cmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "700 700" _null_ _null_ _null_ _null_ btfloat4cmp _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 47a1412..565e455 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -304,6 +304,13 @@ extern Datum btcharcmp(PG_FUNCTION_ARGS);
extern Datum btnamecmp(PG_FUNCTION_ARGS);
extern Datum bttextcmp(PG_FUNCTION_ARGS);
+/*
+ * Per-opclass sort support functions for new btrees. Like the
+ * functions above, these are stored in pg_amproc and defined in
+ * access/nbtree/nbtcompare.c
+ */
+extern Datum btint4sortsupport(PG_FUNCTION_ARGS);
+
/* float.c */
extern PGDLLIMPORT int extra_float_digits;
diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h
new file mode 100644
index 0000000..a925ce1
--- /dev/null
+++ b/src/include/utils/sortsupport.h
@@ -0,0 +1,43 @@
+/*-------------------------------------------------------------------------
+ *
+ * sortsupport.h
+ * Framework for accelerated sorting.
+ *
+ * Sorting can be performed by repeatedly invoking an SQL-callable
+ * comparison function on the value to be compared; this module provides
+ * a way to avoid some of the function call overhead inherent in that
+ * interface. A btree opclass may choose to offer a BTSORTSUPPORT_PROC,
+ * taking a single argument of type internal and returning void.
+ *
+ * This function will be called during sort setup and should initialize
+ * the extra and comparator functions of the SortSupportInfo structure
+ * that will be passed as an argument, using info_cxt for any required
+ * memory allocations. The relevant collation OID will be initialized
+ * prior to invoking this function.
+ *
+ * After initialization, the comparator function will be called directly
+ * for each comparison, eliminating the overhead of the FunctionCallInfo
+ * interface.
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/sortsupport.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SORTSUPPORT_H
+#define SORTSUPPORT_H
+
+typedef struct SortSupportInfoData *SortSupportInfo;
+
+typedef struct SortSupportInfoData
+{
+ MemoryContext info_cxt;
+ void *extra;
+ Oid collation;
+
+ int (*comparator)(Datum a, Datum b, SortSupportInfo info);
+} SortSupportInfoData;
+
+#endif /* SORTSUPPORT_H */
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index b915134..1c8a634 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1186,40 +1186,28 @@ WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- GiST/GIN are special cases because each has an optional support function.
+-- btree/GiST/GIN each allow an optional support function
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
- p1.amname <> 'gist' AND p1.amname <> 'gin' AND
- p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4
- WHERE p4.amprocfamily = p2.oid AND
- p4.amproclefttype = p3.amproclefttype AND
- p4.amprocrighttype = p3.amprocrighttype);
- amname | opfname | amproclefttype | amprocrighttype
---------+---------+----------------+-----------------
-(0 rows)
-
--- Similar check for GiST/GIN, allowing one optional proc
-SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
-FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
-WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
- (p1.amname = 'gist' OR p1.amname = 'gin') AND
- (SELECT count(*) FROM pg_amproc AS p4
- WHERE p4.amprocfamily = p2.oid AND
- p4.amproclefttype = p3.amproclefttype AND
- p4.amprocrighttype = p3.amprocrighttype)
- NOT IN (p1.amsupport, p1.amsupport - 1);
+ p1.amsupport - (SELECT count(*) FROM pg_amproc AS p4
+ WHERE p4.amprocfamily = p2.oid AND
+ p4.amproclefttype = p3.amproclefttype AND
+ p4.amprocrighttype = p3.amprocrighttype)
+ NOT BETWEEN 0 AND
+ CASE WHEN p1.amname IN ('gin', 'gist', 'btree') THEN 1 ELSE 0 END;
amname | opfname | amproclefttype | amprocrighttype
--------+---------+----------------+-----------------
(0 rows)
-- Also, check if there are any pg_opclass entries that don't seem to have
--- pg_amproc support. Again, GiST/GIN have to be checked specially.
+-- pg_amproc support. Again, opclasses with an optional support proc have to be
+-- checked specially.
SELECT amname, opcname, count(*)
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
amproclefttype = amprocrighttype AND amproclefttype = opcintype
-WHERE am.amname <> 'gist' AND am.amname <> 'gin'
+WHERE am.amname <> 'gist' AND am.amname <> 'gin' AND am.amname <> 'btree'
GROUP BY amname, amsupport, opcname, amprocfamily
HAVING count(*) != amsupport OR amprocfamily IS NULL;
amname | opcname | count
@@ -1230,7 +1218,7 @@ SELECT amname, opcname, count(*)
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
amproclefttype = amprocrighttype AND amproclefttype = opcintype
-WHERE am.amname = 'gist' OR am.amname = 'gin'
+WHERE am.amname = 'gist' OR am.amname = 'gin' OR am.amname = 'btree'
GROUP BY amname, amsupport, opcname, amprocfamily
HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
OR amprocfamily IS NULL;
@@ -1261,19 +1249,20 @@ WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND
(0 rows)
-- For btree, though, we can do better since we know the support routines
--- must be of the form cmp(lefttype, righttype) returns int4.
+-- must be of the form cmp(lefttype, righttype) returns int4 or sortsupport(internal).
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
- (amprocnum != 1
- OR proretset
- OR prorettype != 'int4'::regtype
- OR pronargs != 2
- OR proargtypes[0] != amproclefttype
- OR proargtypes[1] != amprocrighttype);
+ (CASE WHEN amprocnum = 1
+ THEN prorettype != 'int4'::regtype OR pronargs != 2
+ OR proargtypes[0] != amproclefttype
+ OR proargtypes[1] != amprocrighttype
+ WHEN amprocnum = 2
+ THEN prorettype != 'void'::regtype OR pronargs != 1
+ OR proargtypes[0] != 'internal'::regtype END);
amprocfamily | amprocnum | oid | proname | opfname
--------------+-----------+-----+---------+---------
(0 rows)
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index b0d1430..1146008 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -926,37 +926,27 @@ WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each datatype combination supported by the opfamily.
--- GiST/GIN are special cases because each has an optional support function.
+-- btree/GiST/GIN each allow an optional support function
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
- p1.amname <> 'gist' AND p1.amname <> 'gin' AND
- p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4
- WHERE p4.amprocfamily = p2.oid AND
- p4.amproclefttype = p3.amproclefttype AND
- p4.amprocrighttype = p3.amprocrighttype);
-
--- Similar check for GiST/GIN, allowing one optional proc
-
-SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
-FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
-WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
- (p1.amname = 'gist' OR p1.amname = 'gin') AND
- (SELECT count(*) FROM pg_amproc AS p4
- WHERE p4.amprocfamily = p2.oid AND
- p4.amproclefttype = p3.amproclefttype AND
- p4.amprocrighttype = p3.amprocrighttype)
- NOT IN (p1.amsupport, p1.amsupport - 1);
+ p1.amsupport - (SELECT count(*) FROM pg_amproc AS p4
+ WHERE p4.amprocfamily = p2.oid AND
+ p4.amproclefttype = p3.amproclefttype AND
+ p4.amprocrighttype = p3.amprocrighttype)
+ NOT BETWEEN 0 AND
+ CASE WHEN p1.amname IN ('gin', 'gist', 'btree') THEN 1 ELSE 0 END;
-- Also, check if there are any pg_opclass entries that don't seem to have
--- pg_amproc support. Again, GiST/GIN have to be checked specially.
+-- pg_amproc support. Again, opclasses with an optional support proc have to be
+-- checked specially.
SELECT amname, opcname, count(*)
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
amproclefttype = amprocrighttype AND amproclefttype = opcintype
-WHERE am.amname <> 'gist' AND am.amname <> 'gin'
+WHERE am.amname <> 'gist' AND am.amname <> 'gin' AND am.amname <> 'btree'
GROUP BY amname, amsupport, opcname, amprocfamily
HAVING count(*) != amsupport OR amprocfamily IS NULL;
@@ -964,7 +954,7 @@ SELECT amname, opcname, count(*)
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
amproclefttype = amprocrighttype AND amproclefttype = opcintype
-WHERE am.amname = 'gist' OR am.amname = 'gin'
+WHERE am.amname = 'gist' OR am.amname = 'gin' OR am.amname = 'btree'
GROUP BY amname, amsupport, opcname, amprocfamily
HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
OR amprocfamily IS NULL;
@@ -990,7 +980,7 @@ WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND
(p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs);
-- For btree, though, we can do better since we know the support routines
--- must be of the form cmp(lefttype, righttype) returns int4.
+-- must be of the form cmp(lefttype, righttype) returns int4 or sortsupport(internal).
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
@@ -998,12 +988,13 @@ SELECT p1.amprocfamily, p1.amprocnum,
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
- (amprocnum != 1
- OR proretset
- OR prorettype != 'int4'::regtype
- OR pronargs != 2
- OR proargtypes[0] != amproclefttype
- OR proargtypes[1] != amprocrighttype);
+ (CASE WHEN amprocnum = 1
+ THEN prorettype != 'int4'::regtype OR pronargs != 2
+ OR proargtypes[0] != amproclefttype
+ OR proargtypes[1] != amprocrighttype
+ WHEN amprocnum = 2
+ THEN prorettype != 'void'::regtype OR pronargs != 1
+ OR proargtypes[0] != 'internal'::regtype END);
-- For hash we can also do a little better: the support routines must be
-- of the form hash(lefttype) returns int4. There are several cases where