LCOV - code coverage report
Current view: top level - src/backend/utils/sort - sortsupport.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 41 46 89.1 %
Date: 2017-09-29 15:12:54 Functions: 5 5 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-2017, 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/nbtree.h"
      19             : #include "catalog/pg_am.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             :     FunctionCallInfoData fcinfo;    /* reusable callinfo structure */
      30             :     FmgrInfo    flinfo;         /* lookup data for comparison function */
      31             : } SortShimExtra;
      32             : 
      33             : 
      34             : /*
      35             :  * Shim function for calling an old-style comparator
      36             :  *
      37             :  * This is essentially an inlined version of FunctionCall2Coll(), except
      38             :  * we assume that the FunctionCallInfoData was already mostly set up by
      39             :  * PrepareSortSupportComparisonShim.
      40             :  */
      41             : static int
      42     1678036 : comparison_shim(Datum x, Datum y, SortSupport ssup)
      43             : {
      44     1678036 :     SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
      45             :     Datum       result;
      46             : 
      47     1678036 :     extra->fcinfo.arg[0] = x;
      48     1678036 :     extra->fcinfo.arg[1] = y;
      49             : 
      50             :     /* just for paranoia's sake, we reset isnull each time */
      51     1678036 :     extra->fcinfo.isnull = false;
      52             : 
      53     1678036 :     result = FunctionCallInvoke(&extra->fcinfo);
      54             : 
      55             :     /* Check for null result, since caller is clearly not expecting one */
      56     1678036 :     if (extra->fcinfo.isnull)
      57           0 :         elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
      58             : 
      59     1678036 :     return result;
      60             : }
      61             : 
      62             : /*
      63             :  * Set up a shim function to allow use of an old-style btree comparison
      64             :  * function as if it were a sort support comparator.
      65             :  */
      66             : void
      67         544 : PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
      68             : {
      69             :     SortShimExtra *extra;
      70             : 
      71         544 :     extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
      72             :                                                  sizeof(SortShimExtra));
      73             : 
      74             :     /* Lookup the comparison function */
      75         544 :     fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
      76             : 
      77             :     /* We can initialize the callinfo just once and re-use it */
      78         544 :     InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
      79             :                              ssup->ssup_collation, NULL, NULL);
      80         544 :     extra->fcinfo.argnull[0] = false;
      81         544 :     extra->fcinfo.argnull[1] = false;
      82             : 
      83         544 :     ssup->ssup_extra = extra;
      84         544 :     ssup->comparator = comparison_shim;
      85         544 : }
      86             : 
      87             : /*
      88             :  * Look up and call sortsupport function to setup SortSupport comparator;
      89             :  * or if no such function exists or it declines to set up the appropriate
      90             :  * state, prepare a suitable shim.
      91             :  */
      92             : static void
      93        9573 : FinishSortSupportFunction(Oid opfamily, Oid opcintype, SortSupport ssup)
      94             : {
      95             :     Oid         sortSupportFunction;
      96             : 
      97             :     /* Look for a sort support function */
      98        9573 :     sortSupportFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
      99             :                                             BTSORTSUPPORT_PROC);
     100        9573 :     if (OidIsValid(sortSupportFunction))
     101             :     {
     102             :         /*
     103             :          * The sort support function can provide a comparator, but it can also
     104             :          * choose not to so (e.g. based on the selected collation).
     105             :          */
     106        9039 :         OidFunctionCall1(sortSupportFunction, PointerGetDatum(ssup));
     107             :     }
     108             : 
     109        9572 :     if (ssup->comparator == NULL)
     110             :     {
     111             :         Oid         sortFunction;
     112             : 
     113         534 :         sortFunction = get_opfamily_proc(opfamily, opcintype, opcintype,
     114             :                                          BTORDER_PROC);
     115             : 
     116         534 :         if (!OidIsValid(sortFunction))
     117           0 :             elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
     118             :                  BTORDER_PROC, opcintype, opcintype, opfamily);
     119             : 
     120             :         /* We'll use a shim to call the old-style btree comparator */
     121         534 :         PrepareSortSupportComparisonShim(sortFunction, ssup);
     122             :     }
     123        9572 : }
     124             : 
     125             : /*
     126             :  * Fill in SortSupport given an ordering operator (btree "<" or ">" operator).
     127             :  *
     128             :  * Caller must previously have zeroed the SortSupportData structure and then
     129             :  * filled in ssup_cxt, ssup_collation, and ssup_nulls_first.  This will fill
     130             :  * in ssup_reverse as well as the comparator function pointer.
     131             :  */
     132             : void
     133        5146 : PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
     134             : {
     135             :     Oid         opfamily;
     136             :     Oid         opcintype;
     137             :     int16       strategy;
     138             : 
     139        5146 :     Assert(ssup->comparator == NULL);
     140             : 
     141             :     /* Find the operator in pg_amop */
     142        5146 :     if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype,
     143             :                                     &strategy))
     144           0 :         elog(ERROR, "operator %u is not a valid ordering operator",
     145             :              orderingOp);
     146        5146 :     ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
     147             : 
     148        5146 :     FinishSortSupportFunction(opfamily, opcintype, ssup);
     149        5145 : }
     150             : 
     151             : /*
     152             :  * Fill in SortSupport given an index relation, attribute, and strategy.
     153             :  *
     154             :  * Caller must previously have zeroed the SortSupportData structure and then
     155             :  * filled in ssup_cxt, ssup_attno, ssup_collation, and ssup_nulls_first.  This
     156             :  * will fill in ssup_reverse (based on the supplied strategy), as well as the
     157             :  * comparator function pointer.
     158             :  */
     159             : void
     160        4427 : PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy,
     161             :                                SortSupport ssup)
     162             : {
     163        4427 :     Oid         opfamily = indexRel->rd_opfamily[ssup->ssup_attno - 1];
     164        4427 :     Oid         opcintype = indexRel->rd_opcintype[ssup->ssup_attno - 1];
     165             : 
     166        4427 :     Assert(ssup->comparator == NULL);
     167             : 
     168        4427 :     if (indexRel->rd_rel->relam != BTREE_AM_OID)
     169           0 :         elog(ERROR, "unexpected non-btree AM: %u", indexRel->rd_rel->relam);
     170        4427 :     if (strategy != BTGreaterStrategyNumber &&
     171             :         strategy != BTLessStrategyNumber)
     172           0 :         elog(ERROR, "unexpected sort support strategy: %d", strategy);
     173        4427 :     ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);
     174             : 
     175        4427 :     FinishSortSupportFunction(opfamily, opcintype, ssup);
     176        4427 : }

Generated by: LCOV version 1.11