LCOV - code coverage report
Current view: top level - src/backend/utils/sort - sortsupport.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 48 55 87.3 %
Date: 2024-04-27 02:11:35 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * sortsupport.c
       4             :  *    Support routines for accelerated sorting.
       5             :  *
       6             :  *
       7             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/sort/sortsupport.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #include "postgres.h"
      17             : 
      18             : #include "access/gist.h"
      19             : #include "access/nbtree.h"
      20             : #include "fmgr.h"
      21             : #include "utils/lsyscache.h"
      22             : #include "utils/rel.h"
      23             : #include "utils/sortsupport.h"
      24             : 
      25             : 
      26             : /* Info needed to use an old-style comparison function as a sort comparator */
      27             : typedef struct
      28             : {
      29             :     FmgrInfo    flinfo;         /* lookup data for comparison function */
      30             :     FunctionCallInfoBaseData fcinfo;    /* reusable callinfo structure */
      31             : } SortShimExtra;
      32             : 
      33             : #define SizeForSortShimExtra(nargs) (offsetof(SortShimExtra, fcinfo) + SizeForFunctionCallInfo(nargs))
      34             : 
      35             : /*
      36             :  * Shim function for calling an old-style comparator
      37             :  *
      38             :  * This is essentially an inlined version of FunctionCall2Coll(), except
      39             :  * we assume that the FunctionCallInfoBaseData was already mostly set up by
      40             :  * PrepareSortSupportComparisonShim.
      41             :  */
      42             : static int
      43    98857108 : comparison_shim(Datum x, Datum y, SortSupport ssup)
      44             : {
      45    98857108 :     SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
      46             :     Datum       result;
      47             : 
      48    98857108 :     extra->fcinfo.args[0].value = x;
      49    98857108 :     extra->fcinfo.args[1].value = y;
      50             : 
      51             :     /* just for paranoia's sake, we reset isnull each time */
      52    98857108 :     extra->fcinfo.isnull = false;
      53             : 
      54    98857108 :     result = FunctionCallInvoke(&extra->fcinfo);
      55             : 
      56             :     /* Check for null result, since caller is clearly not expecting one */
      57    98857108 :     if (extra->fcinfo.isnull)
      58           0 :         elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
      59             : 
      60    98857108 :     return result;
      61             : }
      62             : 
      63             : /*
      64             :  * Set up a shim function to allow use of an old-style btree comparison
      65             :  * function as if it were a sort support comparator.
      66             :  */
      67             : void
      68       24304 : PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
      69             : {
      70             :     SortShimExtra *extra;
      71             : 
      72       24304 :     extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
      73             :                                                  SizeForSortShimExtra(2));
      74             : 
      75             :     /* Lookup the comparison function */
      76       24304 :     fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
      77             : 
      78             :     /* We can initialize the callinfo just once and re-use it */
      79       24304 :     InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
      80             :                              ssup->ssup_collation, NULL, NULL);
      81       24304 :     extra->fcinfo.args[0].isnull = false;
      82       24304 :     extra->fcinfo.args[1].isnull = false;
      83             : 
      84       24304 :     ssup->ssup_extra = extra;
      85       24304 :     ssup->comparator = comparison_shim;
      86       24304 : }
      87             : 
      88             : /*
      89             :  * Look up and call sortsupport function to setup SortSupport comparator;
      90             :  * or if no such function exists or it declines to set up the appropriate
      91             :  * state, prepare a suitable shim.
      92             :  */
      93             : static void
      94      386118 : FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
      95             : {
      96             :     Oid         sortSupportFunction;
      97             : 
      98             :     /* Look for a sort support function */
      99      386118 :     sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
     100             :                                             BTSORTSUPPORT_PROC);
     101      386118 :     if (OidIsValid(sortSupportFunction))
     102             :     {
     103             :         /*
     104             :          * The sort support function can provide a comparator, but it can also
     105             :          * choose not to so (e.g. based on the selected collation).
     106             :          */
     107      362280 :         OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
     108             :     }
     109             : 
     110      386106 :     if (ssup->comparator == NULL)
     111             :     {
     112             :         Oid         sortFunction;
     113             : 
     114       23838 :         sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
     115             :                                          BTORDER_PROC);
     116             : 
     117       23838 :         if (!OidIsValid(sortFunction))
     118           0 :             elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
     119             :                  BTORDER_PROC, opcintype, opcintype, opfamily);
     120             : 
     121             :         /* We'll use a shim to call the old-style btree comparator */
     122       23838 :         PrepareSortSupportComparisonShim(sortFunction, ssup);
     123             :     }
     124      386106 : }
     125             : 
     126             : /*
     127             :  * Fill in SortSupport given an ordering operator (btree "<" or ">" operator).
     128             :  *
     129             :  * Caller must previously have zeroed the SortSupportData structure and then
     130             :  * filled in ssup_cxt, ssup_collation, and ssup_nulls_first.  This will fill
     131             :  * in ssup_reverse as well as the comparator function pointer.
     132             :  */
     133             : void
     134      247452 : PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
     135             : {
     136             :     Oid         opfamily;
     137             :     Oid         opcintype;
     138             :     int16       strategy;
     139             : 
     140             :     Assert(ssup->comparator == NULL);
     141             : 
     142             :     /* Find the operator in pg_amop */
     143      247452 :     if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
     144             :                                     &strategy))
     145           0 :         elog(ERROR, "operator %u is not a valid ordering operator",
     146             :              orderingOp);
     147      247452 :     ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
     148             : 
     149      247452 :     FinishSortSupportFunction(opfamily, opcintype, ssup);
     150      247440 : }
     151             : 
     152             : /*
     153             :  * Fill in SortSupport given an index relation, attribute, and strategy.
     154             :  *
     155             :  * Caller must previously have zeroed the SortSupportData structure and then
     156             :  * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first.  This
     157             :  * will fill in ssup_reverse (based on the supplied strategy), as well as the
     158             :  * comparator function pointer.
     159             :  */
     160             : void
     161      138666 : PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy,
     162             :                                SortSupport ssup)
     163             : {
     164      138666 :     Oid         opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
     165      138666 :     Oid         opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
     166             : 
     167             :     Assert(ssup->comparator == NULL);
     168             : 
     169      138666 :     if (indexRel->rd_rel->relam != BTREE_AM_OID)
     170           0 :         elog(ERROR, "unexpected non-btree AM: %u", indexRel->rd_rel->relam);
     171      138666 :     if (strategy != BTGreaterStrategyNumber &&
     172             :         strategy != BTLessStrategyNumber)
     173           0 :         elog(ERROR, "unexpected sort support strategy: %d", strategy);
     174      138666 :     ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
     175             : 
     176      138666 :     FinishSortSupportFunction(opfamily, opcintype, ssup);
     177      138666 : }
     178             : 
     179             : /*
     180             :  * Fill in SortSupport given a GiST index relation
     181             :  *
     182             :  * Caller must previously have zeroed the SortSupportData structure and then
     183             :  * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first.  This
     184             :  * will fill in ssup_reverse (always false for GiST index build), as well as
     185             :  * the comparator function pointer.
     186             :  */
     187             : void
     188         150 : PrepareSortSupportFromGistIndexRel(Relation indexRel, SortSupport ssup)
     189             : {
     190         150 :     Oid         opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
     191         150 :     Oid         opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
     192             :     Oid         sortSupportFunction;
     193             : 
     194             :     Assert(ssup->comparator == NULL);
     195             : 
     196         150 :     if (indexRel->rd_rel->relam != GIST_AM_OID)
     197           0 :         elog(ERROR, "unexpected non-gist AM: %u", indexRel->rd_rel->relam);
     198         150 :     ssup->ssup_reverse = false;
     199             : 
     200             :     /*
     201             :      * Look up the sort support function. This is simpler than for B-tree
     202             :      * indexes because we don't support the old-style btree comparators.
     203             :      */
     204         150 :     sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
     205             :                                             GIST_SORTSUPPORT_PROC);
     206         150 :     if (!OidIsValid(sortSupportFunction))
     207           0 :         elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
     208             :              GIST_SORTSUPPORT_PROC, opcintype, opcintype, opfamily);
     209         150 :     OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
     210         150 : }

Generated by: LCOV version 1.14