LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tid.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 56 159 35.2 %
Date: 2019-09-19 23:07:04 Functions: 11 19 57.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tid.c
       4             :  *    Functions for the built-in type tuple id
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/adt/tid.c
      12             :  *
      13             :  * NOTES
      14             :  *    input routine largely stolen from boxin().
      15             :  *
      16             :  *-------------------------------------------------------------------------
      17             :  */
      18             : #include "postgres.h"
      19             : 
      20             : #include <math.h>
      21             : #include <limits.h>
      22             : 
      23             : #include "access/heapam.h"
      24             : #include "access/sysattr.h"
      25             : #include "access/tableam.h"
      26             : #include "catalog/namespace.h"
      27             : #include "catalog/pg_type.h"
      28             : #include "libpq/pqformat.h"
      29             : #include "miscadmin.h"
      30             : #include "parser/parsetree.h"
      31             : #include "utils/acl.h"
      32             : #include "utils/builtins.h"
      33             : #include "utils/hashutils.h"
      34             : #include "utils/rel.h"
      35             : #include "utils/snapmgr.h"
      36             : #include "utils/varlena.h"
      37             : 
      38             : 
      39             : #define DatumGetItemPointer(X)   ((ItemPointer) DatumGetPointer(X))
      40             : #define ItemPointerGetDatum(X)   PointerGetDatum(X)
      41             : #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
      42             : #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
      43             : 
      44             : #define LDELIM          '('
      45             : #define RDELIM          ')'
      46             : #define DELIM           ','
      47             : #define NTIDARGS        2
      48             : 
      49             : /* ----------------------------------------------------------------
      50             :  *      tidin
      51             :  * ----------------------------------------------------------------
      52             :  */
      53             : Datum
      54        3166 : tidin(PG_FUNCTION_ARGS)
      55             : {
      56        3166 :     char       *str = PG_GETARG_CSTRING(0);
      57             :     char       *p,
      58             :                *coord[NTIDARGS];
      59             :     int         i;
      60             :     ItemPointer result;
      61             :     BlockNumber blockNumber;
      62             :     OffsetNumber offsetNumber;
      63             :     char       *badp;
      64             :     int         hold_offset;
      65             : 
      66       14772 :     for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
      67       11606 :         if (*p == DELIM || (*p == LDELIM && !i))
      68        6332 :             coord[i++] = p + 1;
      69             : 
      70        3166 :     if (i < NTIDARGS)
      71           0 :         ereport(ERROR,
      72             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      73             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      74             :                         "tid", str)));
      75             : 
      76        3166 :     errno = 0;
      77        3166 :     blockNumber = strtoul(coord[0], &badp, 10);
      78        3166 :     if (errno || *badp != DELIM)
      79           0 :         ereport(ERROR,
      80             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      81             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      82             :                         "tid", str)));
      83             : 
      84        3166 :     hold_offset = strtol(coord[1], &badp, 10);
      85        3166 :     if (errno || *badp != RDELIM ||
      86        3166 :         hold_offset > USHRT_MAX || hold_offset < 0)
      87           0 :         ereport(ERROR,
      88             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      89             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      90             :                         "tid", str)));
      91             : 
      92        3166 :     offsetNumber = hold_offset;
      93             : 
      94        3166 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
      95             : 
      96        3166 :     ItemPointerSet(result, blockNumber, offsetNumber);
      97             : 
      98        3166 :     PG_RETURN_ITEMPOINTER(result);
      99             : }
     100             : 
     101             : /* ----------------------------------------------------------------
     102             :  *      tidout
     103             :  * ----------------------------------------------------------------
     104             :  */
     105             : Datum
     106        3330 : tidout(PG_FUNCTION_ARGS)
     107             : {
     108        3330 :     ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
     109             :     BlockNumber blockNumber;
     110             :     OffsetNumber offsetNumber;
     111             :     char        buf[32];
     112             : 
     113        3330 :     blockNumber = ItemPointerGetBlockNumberNoCheck(itemPtr);
     114        3330 :     offsetNumber = ItemPointerGetOffsetNumberNoCheck(itemPtr);
     115             : 
     116             :     /* Perhaps someday we should output this as a record. */
     117        3330 :     snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
     118             : 
     119        3330 :     PG_RETURN_CSTRING(pstrdup(buf));
     120             : }
     121             : 
     122             : /*
     123             :  *      tidrecv         - converts external binary format to tid
     124             :  */
     125             : Datum
     126           0 : tidrecv(PG_FUNCTION_ARGS)
     127             : {
     128           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     129             :     ItemPointer result;
     130             :     BlockNumber blockNumber;
     131             :     OffsetNumber offsetNumber;
     132             : 
     133           0 :     blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
     134           0 :     offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
     135             : 
     136           0 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
     137             : 
     138           0 :     ItemPointerSet(result, blockNumber, offsetNumber);
     139             : 
     140           0 :     PG_RETURN_ITEMPOINTER(result);
     141             : }
     142             : 
     143             : /*
     144             :  *      tidsend         - converts tid to binary format
     145             :  */
     146             : Datum
     147           0 : tidsend(PG_FUNCTION_ARGS)
     148             : {
     149           0 :     ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
     150             :     StringInfoData buf;
     151             : 
     152           0 :     pq_begintypsend(&buf);
     153           0 :     pq_sendint32(&buf, ItemPointerGetBlockNumberNoCheck(itemPtr));
     154           0 :     pq_sendint16(&buf, ItemPointerGetOffsetNumberNoCheck(itemPtr));
     155           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     156             : }
     157             : 
     158             : /*****************************************************************************
     159             :  *   PUBLIC ROUTINES                                                         *
     160             :  *****************************************************************************/
     161             : 
     162             : Datum
     163     7300106 : tideq(PG_FUNCTION_ARGS)
     164             : {
     165     7300106 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     166     7300106 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     167             : 
     168     7300106 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
     169             : }
     170             : 
     171             : Datum
     172         110 : tidne(PG_FUNCTION_ARGS)
     173             : {
     174         110 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     175         110 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     176             : 
     177         110 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
     178             : }
     179             : 
     180             : Datum
     181        2044 : tidlt(PG_FUNCTION_ARGS)
     182             : {
     183        2044 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     184        2044 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     185             : 
     186        2044 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
     187             : }
     188             : 
     189             : Datum
     190        1600 : tidle(PG_FUNCTION_ARGS)
     191             : {
     192        1600 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     193        1600 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     194             : 
     195        1600 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
     196             : }
     197             : 
     198             : Datum
     199        9244 : tidgt(PG_FUNCTION_ARGS)
     200             : {
     201        9244 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     202        9244 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     203             : 
     204        9244 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
     205             : }
     206             : 
     207             : Datum
     208        1556 : tidge(PG_FUNCTION_ARGS)
     209             : {
     210        1556 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     211        1556 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     212             : 
     213        1556 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
     214             : }
     215             : 
     216             : Datum
     217      207174 : bttidcmp(PG_FUNCTION_ARGS)
     218             : {
     219      207174 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     220      207174 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     221             : 
     222      207174 :     PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
     223             : }
     224             : 
     225             : Datum
     226           0 : tidlarger(PG_FUNCTION_ARGS)
     227             : {
     228           0 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     229           0 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     230             : 
     231           0 :     PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
     232             : }
     233             : 
     234             : Datum
     235           0 : tidsmaller(PG_FUNCTION_ARGS)
     236             : {
     237           0 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     238           0 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     239             : 
     240           0 :     PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
     241             : }
     242             : 
     243             : Datum
     244       80044 : hashtid(PG_FUNCTION_ARGS)
     245             : {
     246       80044 :     ItemPointer key = PG_GETARG_ITEMPOINTER(0);
     247             : 
     248             :     /*
     249             :      * While you'll probably have a lot of trouble with a compiler that
     250             :      * insists on appending pad space to struct ItemPointerData, we can at
     251             :      * least make this code work, by not using sizeof(ItemPointerData).
     252             :      * Instead rely on knowing the sizes of the component fields.
     253             :      */
     254       80044 :     return hash_any((unsigned char *) key,
     255             :                     sizeof(BlockIdData) + sizeof(OffsetNumber));
     256             : }
     257             : 
     258             : Datum
     259           0 : hashtidextended(PG_FUNCTION_ARGS)
     260             : {
     261           0 :     ItemPointer key = PG_GETARG_ITEMPOINTER(0);
     262           0 :     uint64      seed = PG_GETARG_INT64(1);
     263             : 
     264             :     /* As above */
     265           0 :     return hash_any_extended((unsigned char *) key,
     266             :                              sizeof(BlockIdData) + sizeof(OffsetNumber),
     267             :                              seed);
     268             : }
     269             : 
     270             : 
     271             : /*
     272             :  *  Functions to get latest tid of a specified tuple.
     273             :  *
     274             :  *  Maybe these implementations should be moved to another place
     275             :  */
     276             : 
     277             : static ItemPointerData Current_last_tid = {{0, 0}, 0};
     278             : 
     279             : void
     280    11056346 : setLastTid(const ItemPointer tid)
     281             : {
     282    11056346 :     Current_last_tid = *tid;
     283    11056346 : }
     284             : 
     285             : /*
     286             :  *  Handle CTIDs of views.
     287             :  *      CTID should be defined in the view and it must
     288             :  *      correspond to the CTID of a base relation.
     289             :  */
     290             : static Datum
     291           0 : currtid_for_view(Relation viewrel, ItemPointer tid)
     292             : {
     293           0 :     TupleDesc   att = RelationGetDescr(viewrel);
     294             :     RuleLock   *rulelock;
     295             :     RewriteRule *rewrite;
     296             :     int         i,
     297           0 :                 natts = att->natts,
     298           0 :                 tididx = -1;
     299             : 
     300           0 :     for (i = 0; i < natts; i++)
     301             :     {
     302           0 :         Form_pg_attribute attr = TupleDescAttr(att, i);
     303             : 
     304           0 :         if (strcmp(NameStr(attr->attname), "ctid") == 0)
     305             :         {
     306           0 :             if (attr->atttypid != TIDOID)
     307           0 :                 elog(ERROR, "ctid isn't of type TID");
     308           0 :             tididx = i;
     309           0 :             break;
     310             :         }
     311             :     }
     312           0 :     if (tididx < 0)
     313           0 :         elog(ERROR, "currtid cannot handle views with no CTID");
     314           0 :     rulelock = viewrel->rd_rules;
     315           0 :     if (!rulelock)
     316           0 :         elog(ERROR, "the view has no rules");
     317           0 :     for (i = 0; i < rulelock->numLocks; i++)
     318             :     {
     319           0 :         rewrite = rulelock->rules[i];
     320           0 :         if (rewrite->event == CMD_SELECT)
     321             :         {
     322             :             Query      *query;
     323             :             TargetEntry *tle;
     324             : 
     325           0 :             if (list_length(rewrite->actions) != 1)
     326           0 :                 elog(ERROR, "only one select rule is allowed in views");
     327           0 :             query = (Query *) linitial(rewrite->actions);
     328           0 :             tle = get_tle_by_resno(query->targetList, tididx + 1);
     329           0 :             if (tle && tle->expr && IsA(tle->expr, Var))
     330             :             {
     331           0 :                 Var        *var = (Var *) tle->expr;
     332             :                 RangeTblEntry *rte;
     333             : 
     334           0 :                 if (!IS_SPECIAL_VARNO(var->varno) &&
     335           0 :                     var->varattno == SelfItemPointerAttributeNumber)
     336             :                 {
     337           0 :                     rte = rt_fetch(var->varno, query->rtable);
     338           0 :                     if (rte)
     339             :                     {
     340           0 :                         table_close(viewrel, AccessShareLock);
     341           0 :                         return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
     342             :                     }
     343             :                 }
     344             :             }
     345           0 :             break;
     346             :         }
     347             :     }
     348           0 :     elog(ERROR, "currtid cannot handle this view");
     349             :     return (Datum) 0;
     350             : }
     351             : 
     352             : Datum
     353           0 : currtid_byreloid(PG_FUNCTION_ARGS)
     354             : {
     355           0 :     Oid         reloid = PG_GETARG_OID(0);
     356           0 :     ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
     357             :     ItemPointer result;
     358             :     Relation    rel;
     359             :     AclResult   aclresult;
     360             :     Snapshot    snapshot;
     361             :     TableScanDesc scan;
     362             : 
     363           0 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
     364           0 :     if (!reloid)
     365             :     {
     366           0 :         *result = Current_last_tid;
     367           0 :         PG_RETURN_ITEMPOINTER(result);
     368             :     }
     369             : 
     370           0 :     rel = table_open(reloid, AccessShareLock);
     371             : 
     372           0 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     373             :                                   ACL_SELECT);
     374           0 :     if (aclresult != ACLCHECK_OK)
     375           0 :         aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
     376           0 :                        RelationGetRelationName(rel));
     377             : 
     378           0 :     if (rel->rd_rel->relkind == RELKIND_VIEW)
     379           0 :         return currtid_for_view(rel, tid);
     380             : 
     381           0 :     ItemPointerCopy(tid, result);
     382             : 
     383           0 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
     384           0 :     scan = table_beginscan(rel, snapshot, 0, NULL);
     385           0 :     table_tuple_get_latest_tid(scan, result);
     386           0 :     table_endscan(scan);
     387           0 :     UnregisterSnapshot(snapshot);
     388             : 
     389           0 :     table_close(rel, AccessShareLock);
     390             : 
     391           0 :     PG_RETURN_ITEMPOINTER(result);
     392             : }
     393             : 
     394             : Datum
     395           0 : currtid_byrelname(PG_FUNCTION_ARGS)
     396             : {
     397           0 :     text       *relname = PG_GETARG_TEXT_PP(0);
     398           0 :     ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
     399             :     ItemPointer result;
     400             :     RangeVar   *relrv;
     401             :     Relation    rel;
     402             :     AclResult   aclresult;
     403             :     Snapshot    snapshot;
     404             :     TableScanDesc scan;
     405             : 
     406           0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
     407           0 :     rel = table_openrv(relrv, AccessShareLock);
     408             : 
     409           0 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     410             :                                   ACL_SELECT);
     411           0 :     if (aclresult != ACLCHECK_OK)
     412           0 :         aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
     413           0 :                        RelationGetRelationName(rel));
     414             : 
     415           0 :     if (rel->rd_rel->relkind == RELKIND_VIEW)
     416           0 :         return currtid_for_view(rel, tid);
     417             : 
     418           0 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
     419           0 :     ItemPointerCopy(tid, result);
     420             : 
     421           0 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
     422           0 :     scan = table_beginscan(rel, snapshot, 0, NULL);
     423           0 :     table_tuple_get_latest_tid(scan, result);
     424           0 :     table_endscan(scan);
     425           0 :     UnregisterSnapshot(snapshot);
     426             : 
     427           0 :     table_close(rel, AccessShareLock);
     428             : 
     429           0 :     PG_RETURN_ITEMPOINTER(result);
     430             : }

Generated by: LCOV version 1.13