diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 51 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 21 | ||||
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 79 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 39 | ||||
-rw-r--r-- | src/backend/utils/sort/tuplesort.c | 267 |
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(<up, 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); } |