aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/ruleutils.c51
-rw-r--r--src/backend/utils/adt/selfuncs.c21
-rw-r--r--src/backend/utils/cache/lsyscache.c79
-rw-r--r--src/backend/utils/cache/relcache.c39
-rw-r--r--src/backend/utils/sort/tuplesort.c267
5 files changed, 255 insertions, 202 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 34d7b66743b..3c217c98edc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.240 2006/12/29 16:44:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.241 2007/01/09 02:14:14 tgl Exp $
**********************************************************************/
#include "postgres.h"
@@ -615,8 +615,10 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
int keyno;
Oid keycoltype;
Datum indclassDatum;
+ Datum indoptionDatum;
bool isnull;
oidvector *indclass;
+ int2vector *indoption;
StringInfoData buf;
char *str;
char *sep;
@@ -634,11 +636,15 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
indrelid = idxrec->indrelid;
Assert(indexrelid == idxrec->indexrelid);
- /* Must get indclass the hard way */
+ /* Must get indclass and indoption the hard way */
indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
Anum_pg_index_indclass, &isnull);
Assert(!isnull);
indclass = (oidvector *) DatumGetPointer(indclassDatum);
+ indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
+ Anum_pg_index_indoption, &isnull);
+ Assert(!isnull);
+ indoption = (int2vector *) DatumGetPointer(indoptionDatum);
/*
* Fetch the pg_class tuple of the index relation
@@ -707,6 +713,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
for (keyno = 0; keyno < idxrec->indnatts; keyno++)
{
AttrNumber attnum = idxrec->indkey.values[keyno];
+ int16 opt = indoption->values[keyno];
if (!colno)
appendStringInfoString(&buf, sep);
@@ -746,12 +753,28 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
keycoltype = exprType(indexkey);
}
- /*
- * Add the operator class name
- */
+ /* Add the operator class name */
if (!colno)
get_opclass_name(indclass->values[keyno], keycoltype,
&buf);
+
+ /* Add options if relevant */
+ if (amrec->amorderstrategy > 0)
+ {
+ /* if it supports sort ordering, report DESC and NULLS opts */
+ if (opt & INDOPTION_DESC)
+ {
+ appendStringInfo(&buf, " DESC");
+ /* NULLS FIRST is the default in this case */
+ if (!(opt & INDOPTION_NULLS_FIRST))
+ appendStringInfo(&buf, " NULLS LAST");
+ }
+ else
+ {
+ if (opt & INDOPTION_NULLS_FIRST)
+ appendStringInfo(&buf, " NULLS FIRST");
+ }
+ }
}
if (!colno)
@@ -1905,14 +1928,30 @@ get_select_query_def(Query *query, deparse_context *context,
typentry = lookup_type_cache(sortcoltype,
TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
if (srt->sortop == typentry->lt_opr)
- /* ASC is default, so emit nothing */ ;
+ {
+ /* ASC is default, so emit nothing for it */
+ if (srt->nulls_first)
+ appendStringInfo(buf, " NULLS FIRST");
+ }
else if (srt->sortop == typentry->gt_opr)
+ {
appendStringInfo(buf, " DESC");
+ /* DESC defaults to NULLS FIRST */
+ if (!srt->nulls_first)
+ appendStringInfo(buf, " NULLS LAST");
+ }
else
+ {
appendStringInfo(buf, " USING %s",
generate_operator_name(srt->sortop,
sortcoltype,
sortcoltype));
+ /* be specific to eliminate ambiguity */
+ if (srt->nulls_first)
+ appendStringInfo(buf, " NULLS FIRST");
+ else
+ appendStringInfo(buf, " NULLS LAST");
+ }
sep = ", ";
}
}
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 31cc62d68bb..875c7c524af 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.218 2007/01/05 22:19:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.219 2007/01/09 02:14:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -5101,7 +5101,7 @@ btcostestimate(PG_FUNCTION_ARGS)
if (get_attstatsslot(tuple, InvalidOid, 0,
STATISTIC_KIND_CORRELATION,
- index->ordering[0],
+ index->fwdsortop[0],
NULL, NULL, &numbers, &nnumbers))
{
double varCorrelation;
@@ -5116,6 +5116,23 @@ btcostestimate(PG_FUNCTION_ARGS)
free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
}
+ else if (get_attstatsslot(tuple, InvalidOid, 0,
+ STATISTIC_KIND_CORRELATION,
+ index->revsortop[0],
+ NULL, NULL, &numbers, &nnumbers))
+ {
+ double varCorrelation;
+
+ Assert(nnumbers == 1);
+ varCorrelation = numbers[0];
+
+ if (index->ncolumns > 1)
+ *indexCorrelation = - varCorrelation * 0.75;
+ else
+ *indexCorrelation = - varCorrelation;
+
+ free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
+ }
ReleaseSysCache(tuple);
}
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 82dbca9e116..6379e258126 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.141 2007/01/05 22:19:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.142 2007/01/09 02:14:14 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -16,6 +16,7 @@
#include "postgres.h"
#include "access/hash.h"
+#include "access/nbtree.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
@@ -192,7 +193,7 @@ get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
if (op_form->amopstrategy != BTEqualStrategyNumber)
continue;
- /* See if sort operator is also in this opclass with OK semantics */
+ /* See if sort operator is also in this opfamily with OK semantics */
opfamily_id = op_form->amopfamily;
op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
if (op_strategy == BTLessStrategyNumber ||
@@ -285,6 +286,78 @@ get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
#endif
/*
+ * get_op_compare_function
+ * Get the OID of the datatype-specific btree comparison function
+ * associated with an ordering operator (a "<" or ">" operator).
+ *
+ * *cmpfunc receives the comparison function OID.
+ * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
+ * (indicating the comparison result must be negated before use).
+ *
+ * Returns TRUE if successful, FALSE if no btree function can be found.
+ * (This indicates that the operator is not a valid ordering operator.)
+ */
+bool
+get_op_compare_function(Oid opno, Oid *cmpfunc, bool *reverse)
+{
+ bool result = false;
+ CatCList *catlist;
+ int i;
+
+ /* ensure outputs are set on failure */
+ *cmpfunc = InvalidOid;
+ *reverse = false;
+
+ /*
+ * Search pg_amop to see if the target operator is registered as the "<"
+ * or ">" operator of any btree opfamily. It's possible that it might be
+ * registered both ways (if someone were to build a "reverse sort"
+ * opfamily); assume we can use either interpretation. (Note: the
+ * existence of a reverse-sort opfamily would result in uncertainty as
+ * to whether "ORDER BY USING op" would default to NULLS FIRST or NULLS
+ * LAST. Since there is no longer any particularly good reason to build
+ * reverse-sort opfamilies, we don't bother expending any extra work to
+ * make this more determinate. In practice, because of the way the
+ * syscache search works, we'll use the interpretation associated with
+ * the opfamily with smallest OID, which is probably determinate enough.)
+ */
+ catlist = SearchSysCacheList(AMOPOPID, 1,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple tuple = &catlist->members[i]->tuple;
+ Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+
+ /* must be btree */
+ if (aform->amopmethod != BTREE_AM_OID)
+ continue;
+
+ if (aform->amopstrategy == BTLessStrategyNumber ||
+ aform->amopstrategy == BTGreaterStrategyNumber)
+ {
+ /* Found a suitable opfamily, get matching support function */
+ *reverse = (aform->amopstrategy == BTGreaterStrategyNumber);
+ *cmpfunc = get_opfamily_proc(aform->amopfamily,
+ aform->amoplefttype,
+ aform->amoprighttype,
+ BTORDER_PROC);
+ if (!OidIsValid(*cmpfunc)) /* should not happen */
+ elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
+ BTORDER_PROC, aform->amoplefttype, aform->amoprighttype,
+ aform->amopfamily);
+ result = true;
+ break;
+ }
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ return result;
+}
+
+/*
* get_op_hash_function
* Get the OID of the datatype-specific hash function associated with
* a hashable equality operator.
@@ -298,9 +371,9 @@ get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
Oid
get_op_hash_function(Oid opno)
{
+ Oid result = InvalidOid;
CatCList *catlist;
int i;
- Oid result = InvalidOid;
/*
* Search pg_amop to see if the target operator is registered as the "="
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index baa45447a29..c43846cd57a 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.253 2007/01/05 22:19:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.254 2007/01/09 02:14:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -925,8 +925,10 @@ RelationInitIndexAccessInfo(Relation relation)
HeapTuple tuple;
Form_pg_am aform;
Datum indclassDatum;
+ Datum indoptionDatum;
bool isnull;
oidvector *indclass;
+ int2vector *indoption;
MemoryContext indexcxt;
MemoryContext oldcontext;
int natts;
@@ -1019,6 +1021,9 @@ RelationInitIndexAccessInfo(Relation relation)
relation->rd_supportinfo = NULL;
}
+ relation->rd_indoption = (int16 *)
+ MemoryContextAllocZero(indexcxt, natts * sizeof(int16));
+
/*
* indclass cannot be referenced directly through the C struct, because it
* comes after the variable-width indkey field. Must extract the
@@ -1042,6 +1047,17 @@ RelationInitIndexAccessInfo(Relation relation)
amstrategies, amsupport, natts);
/*
+ * Similarly extract indoption and copy it to the cache entry
+ */
+ indoptionDatum = fastgetattr(relation->rd_indextuple,
+ Anum_pg_index_indoption,
+ GetPgIndexDescriptor(),
+ &isnull);
+ Assert(!isnull);
+ indoption = (int2vector *) DatumGetPointer(indoptionDatum);
+ memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16));
+
+ /*
* expressions and predicate cache will be filled later
*/
relation->rd_indexprs = NIL;
@@ -3237,6 +3253,7 @@ load_relcache_init_file(void)
Oid *operator;
RegProcedure *support;
int nsupport;
+ int16 *indoption;
/* Count nailed indexes to ensure we have 'em all */
if (rel->rd_isnailed)
@@ -3304,7 +3321,7 @@ load_relcache_init_file(void)
rel->rd_operator = operator;
- /* finally, read the vector of support procedures */
+ /* next, read the vector of support procedures */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
@@ -3313,6 +3330,16 @@ load_relcache_init_file(void)
rel->rd_support = support;
+ /* finally, read the vector of indoption values */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
+
+ indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
+ if ((nread = fread(indoption, 1, len, fp)) != len)
+ goto read_failed;
+
+ rel->rd_indoption = indoption;
+
/* set up zeroed fmgr-info vectors */
rel->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
@@ -3336,6 +3363,7 @@ load_relcache_init_file(void)
Assert(rel->rd_operator == NULL);
Assert(rel->rd_support == NULL);
Assert(rel->rd_supportinfo == NULL);
+ Assert(rel->rd_indoption == NULL);
}
/*
@@ -3525,10 +3553,15 @@ write_relcache_init_file(void)
relform->relnatts * (am->amstrategies * sizeof(Oid)),
fp);
- /* finally, write the vector of support procedures */
+ /* next, write the vector of support procedures */
write_item(rel->rd_support,
relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
+
+ /* finally, write the vector of indoption values */
+ write_item(rel->rd_indoption,
+ relform->relnatts * sizeof(int16),
+ fp);
}
/* also make a list of their OIDs, for RelationIdIsInInitFile */
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index f410aedda25..63c2fec28ea 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -91,7 +91,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.72 2007/01/05 22:19:47 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.73 2007/01/09 02:14:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -315,7 +315,6 @@ struct Tuplesortstate
*/
TupleDesc tupDesc;
ScanKey scanKeys; /* array of length nKeys */
- SortFunctionKind *sortFnKinds; /* array of length nKeys */
/*
* These variables are specific to the IndexTuple case; they are set by
@@ -330,9 +329,8 @@ struct Tuplesortstate
* tuplesort_begin_datum and used only by the DatumTuple routines.
*/
Oid datumType;
- Oid sortOperator;
FmgrInfo sortOpFn; /* cached lookup data for sortOperator */
- SortFunctionKind sortFnKind;
+ int sortFnFlags; /* equivalent to sk_flags */
/* we need typelen and byval in order to know how to copy the Datums. */
int datumTypeLen;
bool datumTypeByVal;
@@ -515,8 +513,8 @@ tuplesort_begin_common(int workMem, bool randomAccess)
Tuplesortstate *
tuplesort_begin_heap(TupleDesc tupDesc,
- int nkeys,
- Oid *sortOperators, AttrNumber *attNums,
+ int nkeys, AttrNumber *attNums,
+ Oid *sortOperators, bool *nullsFirstFlags,
int workMem, bool randomAccess)
{
Tuplesortstate *state = tuplesort_begin_common(workMem, randomAccess);
@@ -543,19 +541,19 @@ tuplesort_begin_heap(TupleDesc tupDesc,
state->tupDesc = tupDesc; /* assume we need not copy tupDesc */
state->scanKeys = (ScanKey) palloc0(nkeys * sizeof(ScanKeyData));
- state->sortFnKinds = (SortFunctionKind *)
- palloc0(nkeys * sizeof(SortFunctionKind));
for (i = 0; i < nkeys; i++)
{
- RegProcedure sortFunction;
+ Oid sortFunction;
+ bool reverse;
- AssertArg(sortOperators[i] != 0);
AssertArg(attNums[i] != 0);
+ AssertArg(sortOperators[i] != 0);
- /* select a function that implements the sort operator */
- SelectSortFunction(sortOperators[i], &sortFunction,
- &state->sortFnKinds[i]);
+ if (!get_op_compare_function(sortOperators[i],
+ &sortFunction, &reverse))
+ elog(ERROR, "operator %u is not a valid ordering operator",
+ sortOperators[i]);
/*
* We needn't fill in sk_strategy or sk_subtype since these scankeys
@@ -566,6 +564,12 @@ tuplesort_begin_heap(TupleDesc tupDesc,
InvalidStrategy,
sortFunction,
(Datum) 0);
+
+ /* However, we use btree's conventions for encoding directionality */
+ if (reverse)
+ state->scanKeys[i].sk_flags |= SK_BT_DESC;
+ if (nullsFirstFlags[i])
+ state->scanKeys[i].sk_flags |= SK_BT_NULLS_FIRST;
}
MemoryContextSwitchTo(oldcontext);
@@ -610,12 +614,13 @@ tuplesort_begin_index(Relation indexRel,
Tuplesortstate *
tuplesort_begin_datum(Oid datumType,
- Oid sortOperator,
+ Oid sortOperator, bool nullsFirstFlag,
int workMem, bool randomAccess)
{
Tuplesortstate *state = tuplesort_begin_common(workMem, randomAccess);
MemoryContext oldcontext;
- RegProcedure sortFunction;
+ Oid sortFunction;
+ bool reverse;
int16 typlen;
bool typbyval;
@@ -636,13 +641,19 @@ tuplesort_begin_datum(Oid datumType,
state->readtup = readtup_datum;
state->datumType = datumType;
- state->sortOperator = sortOperator;
- /* select a function that implements the sort operator */
- SelectSortFunction(sortOperator, &sortFunction, &state->sortFnKind);
- /* and look up the function */
+ /* lookup the ordering function */
+ if (!get_op_compare_function(sortOperator,
+ &sortFunction, &reverse))
+ elog(ERROR, "operator %u is not a valid ordering operator",
+ sortOperator);
fmgr_info(sortFunction, &state->sortOpFn);
+ /* set ordering flags */
+ state->sortFnFlags = reverse ? SK_BT_DESC : 0;
+ if (nullsFirstFlag)
+ state->sortFnFlags |= SK_BT_NULLS_FIRST;
+
/* lookup necessary attributes of the datum type */
get_typlenbyval(datumType, &typlen, &typbyval);
state->datumTypeLen = typlen;
@@ -2083,106 +2094,26 @@ markrunend(Tuplesortstate *state, int tapenum)
/*
- * This routine selects an appropriate sorting function to implement
- * a sort operator as efficiently as possible. The straightforward
- * method is to use the operator's implementation proc --- ie, "<"
- * comparison. However, that way often requires two calls of the function
- * per comparison. If we can find a btree three-way comparator function
- * associated with the operator, we can use it to do the comparisons
- * more efficiently. We also support the possibility that the operator
- * is ">" (descending sort), in which case we have to reverse the output
- * of the btree comparator.
- *
- * Possibly this should live somewhere else (backend/catalog/, maybe?).
+ * Set up for an external caller of ApplySortFunction. This function
+ * basically just exists to localize knowledge of the encoding of sk_flags
+ * used in this module.
*/
void
SelectSortFunction(Oid sortOperator,
- RegProcedure *sortFunction,
- SortFunctionKind *kind)
+ bool nulls_first,
+ Oid *sortFunction,
+ int *sortFlags)
{
- CatCList *catlist;
- int i;
- HeapTuple tuple;
- Form_pg_operator optup;
- Oid opfamily = InvalidOid;
- Oid opinputtype = InvalidOid;
+ bool reverse;
- /*
- * Search pg_amop to see if the target operator is registered as a "<"
- * or ">" operator of any btree opfamily. It's possible that it might be
- * registered both ways (eg, if someone were to build a "reverse sort"
- * opfamily); prefer the "<" case if so. If the operator is registered the
- * same way in multiple opfamilies, assume we can use the associated
- * comparator function from any one.
- */
- catlist = SearchSysCacheList(AMOPOPID, 1,
- ObjectIdGetDatum(sortOperator),
- 0, 0, 0);
-
- for (i = 0; i < catlist->n_members; i++)
- {
- Form_pg_amop aform;
+ if (!get_op_compare_function(sortOperator,
+ sortFunction, &reverse))
+ elog(ERROR, "operator %u is not a valid ordering operator",
+ sortOperator);
- tuple = &catlist->members[i]->tuple;
- aform = (Form_pg_amop) GETSTRUCT(tuple);
-
- /* must be btree */
- if (aform->amopmethod != BTREE_AM_OID)
- continue;
- /* mustn't be cross-datatype, either */
- if (aform->amoplefttype != aform->amoprighttype)
- continue;
-
- if (aform->amopstrategy == BTLessStrategyNumber)
- {
- opfamily = aform->amopfamily;
- opinputtype = aform->amoplefttype;
- *kind = SORTFUNC_CMP;
- break; /* done looking */
- }
- else if (aform->amopstrategy == BTGreaterStrategyNumber)
- {
- opfamily = aform->amopfamily;
- opinputtype = aform->amoplefttype;
- *kind = SORTFUNC_REVCMP;
- /* keep scanning in hopes of finding a BTLess entry */
- }
- }
-
- ReleaseSysCacheList(catlist);
-
- if (OidIsValid(opfamily))
- {
- /* Found a suitable opfamily, get the matching comparator function */
- *sortFunction = get_opfamily_proc(opfamily,
- opinputtype,
- opinputtype,
- BTORDER_PROC);
- Assert(RegProcedureIsValid(*sortFunction));
- return;
- }
-
- /*
- * Can't find a comparator, so use the operator as-is. Decide whether it
- * is forward or reverse sort by looking at its name (grotty, but this
- * only matters for deciding which end NULLs should get sorted to). XXX
- * possibly better idea: see whether its selectivity function is
- * scalargtcmp?
- */
- tuple = SearchSysCache(OPEROID,
- ObjectIdGetDatum(sortOperator),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for operator %u", sortOperator);
- optup = (Form_pg_operator) GETSTRUCT(tuple);
- if (strcmp(NameStr(optup->oprname), ">") == 0)
- *kind = SORTFUNC_REVLT;
- else
- *kind = SORTFUNC_LT;
- *sortFunction = optup->oprcode;
- ReleaseSysCache(tuple);
-
- Assert(RegProcedureIsValid(*sortFunction));
+ *sortFlags = reverse ? SK_BT_DESC : 0;
+ if (nulls_first)
+ *sortFlags |= SK_BT_NULLS_FIRST;
}
/*
@@ -2213,74 +2144,42 @@ myFunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
/*
* Apply a sort function (by now converted to fmgr lookup form)
* and return a 3-way comparison result. This takes care of handling
- * NULLs and sort ordering direction properly.
+ * reverse-sort and NULLs-ordering properly. We assume that DESC and
+ * NULLS_FIRST options are encoded in sk_flags the same way btree does it.
*/
static inline int32
-inlineApplySortFunction(FmgrInfo *sortFunction, SortFunctionKind kind,
+inlineApplySortFunction(FmgrInfo *sortFunction, int sk_flags,
Datum datum1, bool isNull1,
Datum datum2, bool isNull2)
{
- switch (kind)
- {
- case SORTFUNC_LT:
- if (isNull1)
- {
- if (isNull2)
- return 0;
- return 1; /* NULL sorts after non-NULL */
- }
- if (isNull2)
- return -1;
- if (DatumGetBool(myFunctionCall2(sortFunction, datum1, datum2)))
- return -1; /* a < b */
- if (DatumGetBool(myFunctionCall2(sortFunction, datum2, datum1)))
- return 1; /* a > b */
- return 0;
-
- case SORTFUNC_REVLT:
- /* We reverse the ordering of NULLs, but not the operator */
- if (isNull1)
- {
- if (isNull2)
- return 0;
- return -1; /* NULL sorts before non-NULL */
- }
- if (isNull2)
- return 1;
- if (DatumGetBool(myFunctionCall2(sortFunction, datum1, datum2)))
- return -1; /* a < b */
- if (DatumGetBool(myFunctionCall2(sortFunction, datum2, datum1)))
- return 1; /* a > b */
- return 0;
-
- case SORTFUNC_CMP:
- if (isNull1)
- {
- if (isNull2)
- return 0;
- return 1; /* NULL sorts after non-NULL */
- }
- if (isNull2)
- return -1;
- return DatumGetInt32(myFunctionCall2(sortFunction,
- datum1, datum2));
+ int32 compare;
- case SORTFUNC_REVCMP:
- if (isNull1)
- {
- if (isNull2)
- return 0;
- return -1; /* NULL sorts before non-NULL */
- }
- if (isNull2)
- return 1;
- return -DatumGetInt32(myFunctionCall2(sortFunction,
- datum1, datum2));
+ if (isNull1)
+ {
+ if (isNull2)
+ compare = 0; /* NULL "=" NULL */
+ else if (sk_flags & SK_BT_NULLS_FIRST)
+ compare = -1; /* NULL "<" NOT_NULL */
+ else
+ compare = 1; /* NULL ">" NOT_NULL */
+ }
+ else if (isNull2)
+ {
+ if (sk_flags & SK_BT_NULLS_FIRST)
+ compare = 1; /* NOT_NULL ">" NULL */
+ else
+ compare = -1; /* NOT_NULL "<" NULL */
+ }
+ else
+ {
+ compare = DatumGetInt32(myFunctionCall2(sortFunction,
+ datum1, datum2));
- default:
- elog(ERROR, "unrecognized SortFunctionKind: %d", (int) kind);
- return 0; /* can't get here, but keep compiler quiet */
+ if (sk_flags & SK_BT_DESC)
+ compare = -compare;
}
+
+ return compare;
}
/*
@@ -2288,11 +2187,11 @@ inlineApplySortFunction(FmgrInfo *sortFunction, SortFunctionKind kind,
* C99's brain-dead notions about how to implement inline functions...
*/
int32
-ApplySortFunction(FmgrInfo *sortFunction, SortFunctionKind kind,
+ApplySortFunction(FmgrInfo *sortFunction, int sortFlags,
Datum datum1, bool isNull1,
Datum datum2, bool isNull2)
{
- return inlineApplySortFunction(sortFunction, kind,
+ return inlineApplySortFunction(sortFunction, sortFlags,
datum1, isNull1,
datum2, isNull2);
}
@@ -2316,8 +2215,7 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
CHECK_FOR_INTERRUPTS();
/* Compare the leading sort key */
- compare = inlineApplySortFunction(&scanKey->sk_func,
- state->sortFnKinds[0],
+ compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
if (compare != 0)
@@ -2341,8 +2239,7 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
- compare = inlineApplySortFunction(&scanKey->sk_func,
- state->sortFnKinds[nkey],
+ compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
datum1, isnull1,
datum2, isnull2);
if (compare != 0)
@@ -2457,8 +2354,7 @@ comparetup_index(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
CHECK_FOR_INTERRUPTS();
/* Compare the leading sort key */
- compare = inlineApplySortFunction(&scanKey->sk_func,
- SORTFUNC_CMP,
+ compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
if (compare != 0)
@@ -2484,14 +2380,9 @@ comparetup_index(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
- /* see comments about NULLs handling in btbuild */
-
- /* the comparison function is always of CMP type */
- compare = inlineApplySortFunction(&scanKey->sk_func,
- SORTFUNC_CMP,
+ compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
datum1, isnull1,
datum2, isnull2);
-
if (compare != 0)
return compare; /* done when we find unequal attributes */
@@ -2617,7 +2508,7 @@ comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
/* Allow interrupting long sorts */
CHECK_FOR_INTERRUPTS();
- return inlineApplySortFunction(&state->sortOpFn, state->sortFnKind,
+ return inlineApplySortFunction(&state->sortOpFn, state->sortFnFlags,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
}