mirror of
https://github.com/postgres/postgres.git
synced 2025-10-16 17:07:43 +03:00
Create a "sort support" interface API for faster sorting.
This patch creates an API whereby a btree index opclass can optionally provide non-SQL-callable support functions for sorting. In the initial patch, we only use this to provide a directly-callable comparator function, which can be invoked with a bit less overhead than the traditional SQL-callable comparator. While that should be of value in itself, the real reason for doing this is to provide a datatype-extensible framework for more aggressive optimizations, as in Peter Geoghegan's recent work. Robert Haas and Tom Lane
This commit is contained in:
@@ -47,8 +47,8 @@
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/pg_rusage.h"
|
||||
#include "utils/sortsupport.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/tuplesort.h"
|
||||
#include "utils/timestamp.h"
|
||||
#include "utils/tqual.h"
|
||||
|
||||
@@ -1774,8 +1774,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FmgrInfo *cmpFn;
|
||||
int cmpFlags;
|
||||
SortSupport ssup;
|
||||
int *tupnoLink;
|
||||
} CompareScalarsContext;
|
||||
|
||||
@@ -2222,9 +2221,7 @@ compute_scalar_stats(VacAttrStatsP stats,
|
||||
bool is_varwidth = (!stats->attrtype->typbyval &&
|
||||
stats->attrtype->typlen < 0);
|
||||
double corr_xysum;
|
||||
Oid cmpFn;
|
||||
int cmpFlags;
|
||||
FmgrInfo f_cmpfn;
|
||||
SortSupportData ssup;
|
||||
ScalarItem *values;
|
||||
int values_cnt = 0;
|
||||
int *tupnoLink;
|
||||
@@ -2238,8 +2235,13 @@ compute_scalar_stats(VacAttrStatsP stats,
|
||||
tupnoLink = (int *) palloc(samplerows * sizeof(int));
|
||||
track = (ScalarMCVItem *) palloc(num_mcv * sizeof(ScalarMCVItem));
|
||||
|
||||
SelectSortFunction(mystats->ltopr, false, &cmpFn, &cmpFlags);
|
||||
fmgr_info(cmpFn, &f_cmpfn);
|
||||
memset(&ssup, 0, sizeof(ssup));
|
||||
ssup.ssup_cxt = CurrentMemoryContext;
|
||||
/* We always use the default collation for statistics */
|
||||
ssup.ssup_collation = DEFAULT_COLLATION_OID;
|
||||
ssup.ssup_nulls_first = false;
|
||||
|
||||
PrepareSortSupportFromOrderingOp(mystats->ltopr, &ssup);
|
||||
|
||||
/* Initial scan to find sortable values */
|
||||
for (i = 0; i < samplerows; i++)
|
||||
@@ -2307,8 +2309,7 @@ compute_scalar_stats(VacAttrStatsP stats,
|
||||
CompareScalarsContext cxt;
|
||||
|
||||
/* Sort the collected values */
|
||||
cxt.cmpFn = &f_cmpfn;
|
||||
cxt.cmpFlags = cmpFlags;
|
||||
cxt.ssup = &ssup;
|
||||
cxt.tupnoLink = tupnoLink;
|
||||
qsort_arg((void *) values, values_cnt, sizeof(ScalarItem),
|
||||
compare_scalars, (void *) &cxt);
|
||||
@@ -2712,12 +2713,9 @@ compare_scalars(const void *a, const void *b, void *arg)
|
||||
Datum db = ((const ScalarItem *) b)->value;
|
||||
int tb = ((const ScalarItem *) b)->tupno;
|
||||
CompareScalarsContext *cxt = (CompareScalarsContext *) arg;
|
||||
int32 compare;
|
||||
int compare;
|
||||
|
||||
/* We always use the default collation for statistics */
|
||||
compare = ApplySortFunction(cxt->cmpFn, cxt->cmpFlags,
|
||||
DEFAULT_COLLATION_OID,
|
||||
da, false, db, false);
|
||||
compare = ApplySortComparator(da, false, db, false, cxt->ssup);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/nbtree.h"
|
||||
#include "access/sysattr.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
@@ -1151,27 +1152,48 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
|
||||
procform = (Form_pg_proc) GETSTRUCT(proctup);
|
||||
|
||||
/*
|
||||
* btree support procs must be 2-arg procs returning int4; hash support
|
||||
* procs must be 1-arg procs returning int4; otherwise we don't know.
|
||||
* btree comparison procs must be 2-arg procs returning int4, while btree
|
||||
* sortsupport procs must take internal and return void. hash support
|
||||
* procs must be 1-arg procs returning int4. Otherwise we don't know.
|
||||
*/
|
||||
if (amoid == BTREE_AM_OID)
|
||||
{
|
||||
if (procform->pronargs != 2)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("btree procedures must have two arguments")));
|
||||
if (procform->prorettype != INT4OID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("btree procedures must return integer")));
|
||||
if (member->number == BTORDER_PROC)
|
||||
{
|
||||
if (procform->pronargs != 2)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("btree comparison procedures must have two arguments")));
|
||||
if (procform->prorettype != INT4OID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("btree comparison procedures must return integer")));
|
||||
|
||||
/*
|
||||
* If lefttype/righttype isn't specified, use the proc's input types
|
||||
*/
|
||||
if (!OidIsValid(member->lefttype))
|
||||
member->lefttype = procform->proargtypes.values[0];
|
||||
if (!OidIsValid(member->righttype))
|
||||
member->righttype = procform->proargtypes.values[1];
|
||||
/*
|
||||
* If lefttype/righttype isn't specified, use the proc's input
|
||||
* types
|
||||
*/
|
||||
if (!OidIsValid(member->lefttype))
|
||||
member->lefttype = procform->proargtypes.values[0];
|
||||
if (!OidIsValid(member->righttype))
|
||||
member->righttype = procform->proargtypes.values[1];
|
||||
}
|
||||
else if (member->number == BTSORTSUPPORT_PROC)
|
||||
{
|
||||
if (procform->pronargs != 1 ||
|
||||
procform->proargtypes.values[0] != INTERNALOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("btree sort support procedures must accept type \"internal\"")));
|
||||
if (procform->prorettype != VOIDOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("btree sort support procedures must return void")));
|
||||
|
||||
/*
|
||||
* Can't infer lefttype/righttype from proc, so use default rule
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if (amoid == HASH_AM_OID)
|
||||
{
|
||||
@@ -1192,23 +1214,21 @@ assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
|
||||
if (!OidIsValid(member->righttype))
|
||||
member->righttype = procform->proargtypes.values[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* The default for GiST and GIN in CREATE OPERATOR CLASS is to use the
|
||||
* class' opcintype as lefttype and righttype. In CREATE or ALTER
|
||||
* OPERATOR FAMILY, opcintype isn't available, so make the user
|
||||
* specify the types.
|
||||
*/
|
||||
if (!OidIsValid(member->lefttype))
|
||||
member->lefttype = typeoid;
|
||||
if (!OidIsValid(member->righttype))
|
||||
member->righttype = typeoid;
|
||||
if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("associated data types must be specified for index support procedure")));
|
||||
}
|
||||
|
||||
/*
|
||||
* The default in CREATE OPERATOR CLASS is to use the class' opcintype as
|
||||
* lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
|
||||
* isn't available, so make the user specify the types.
|
||||
*/
|
||||
if (!OidIsValid(member->lefttype))
|
||||
member->lefttype = typeoid;
|
||||
if (!OidIsValid(member->righttype))
|
||||
member->righttype = typeoid;
|
||||
|
||||
if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("associated data types must be specified for index support procedure")));
|
||||
|
||||
ReleaseSysCache(proctup);
|
||||
}
|
||||
|
Reference in New Issue
Block a user