LCOV - code coverage report
Current view: top level - src/backend/utils/adt - tid.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 53 148 35.8 %
Date: 2017-09-29 13:40:31 Functions: 10 17 58.8 %
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-2017, 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 "catalog/namespace.h"
      26             : #include "catalog/pg_type.h"
      27             : #include "libpq/pqformat.h"
      28             : #include "miscadmin.h"
      29             : #include "parser/parsetree.h"
      30             : #include "utils/acl.h"
      31             : #include "utils/builtins.h"
      32             : #include "utils/rel.h"
      33             : #include "utils/snapmgr.h"
      34             : #include "utils/tqual.h"
      35             : #include "utils/varlena.h"
      36             : 
      37             : 
      38             : #define DatumGetItemPointer(X)   ((ItemPointer) DatumGetPointer(X))
      39             : #define ItemPointerGetDatum(X)   PointerGetDatum(X)
      40             : #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
      41             : #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
      42             : 
      43             : #define LDELIM          '('
      44             : #define RDELIM          ')'
      45             : #define DELIM           ','
      46             : #define NTIDARGS        2
      47             : 
      48             : /* ----------------------------------------------------------------
      49             :  *      tidin
      50             :  * ----------------------------------------------------------------
      51             :  */
      52             : Datum
      53         155 : tidin(PG_FUNCTION_ARGS)
      54             : {
      55         155 :     char       *str = PG_GETARG_CSTRING(0);
      56             :     char       *p,
      57             :                *coord[NTIDARGS];
      58             :     int         i;
      59             :     ItemPointer result;
      60             :     BlockNumber blockNumber;
      61             :     OffsetNumber offsetNumber;
      62             :     char       *badp;
      63             :     int         hold_offset;
      64             : 
      65         980 :     for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
      66         825 :         if (*p == DELIM || (*p == LDELIM && !i))
      67         310 :             coord[i++] = p + 1;
      68             : 
      69         155 :     if (i < NTIDARGS)
      70           0 :         ereport(ERROR,
      71             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      72             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      73             :                         "tid", str)));
      74             : 
      75         155 :     errno = 0;
      76         155 :     blockNumber = strtoul(coord[0], &badp, 10);
      77         155 :     if (errno || *badp != DELIM)
      78           0 :         ereport(ERROR,
      79             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      80             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      81             :                         "tid", str)));
      82             : 
      83         155 :     hold_offset = strtol(coord[1], &badp, 10);
      84         155 :     if (errno || *badp != RDELIM ||
      85         155 :         hold_offset > USHRT_MAX || hold_offset < 0)
      86           0 :         ereport(ERROR,
      87             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      88             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      89             :                         "tid", str)));
      90             : 
      91         155 :     offsetNumber = hold_offset;
      92             : 
      93         155 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
      94             : 
      95         155 :     ItemPointerSet(result, blockNumber, offsetNumber);
      96             : 
      97         155 :     PG_RETURN_ITEMPOINTER(result);
      98             : }
      99             : 
     100             : /* ----------------------------------------------------------------
     101             :  *      tidout
     102             :  * ----------------------------------------------------------------
     103             :  */
     104             : Datum
     105          79 : tidout(PG_FUNCTION_ARGS)
     106             : {
     107          79 :     ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
     108             :     BlockNumber blockNumber;
     109             :     OffsetNumber offsetNumber;
     110             :     char        buf[32];
     111             : 
     112          79 :     blockNumber = ItemPointerGetBlockNumberNoCheck(itemPtr);
     113          79 :     offsetNumber = ItemPointerGetOffsetNumberNoCheck(itemPtr);
     114             : 
     115             :     /* Perhaps someday we should output this as a record. */
     116          79 :     snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
     117             : 
     118          79 :     PG_RETURN_CSTRING(pstrdup(buf));
     119             : }
     120             : 
     121             : /*
     122             :  *      tidrecv         - converts external binary format to tid
     123             :  */
     124             : Datum
     125           0 : tidrecv(PG_FUNCTION_ARGS)
     126             : {
     127           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     128             :     ItemPointer result;
     129             :     BlockNumber blockNumber;
     130             :     OffsetNumber offsetNumber;
     131             : 
     132           0 :     blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
     133           0 :     offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
     134             : 
     135           0 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
     136             : 
     137           0 :     ItemPointerSet(result, blockNumber, offsetNumber);
     138             : 
     139           0 :     PG_RETURN_ITEMPOINTER(result);
     140             : }
     141             : 
     142             : /*
     143             :  *      tidsend         - converts tid to binary format
     144             :  */
     145             : Datum
     146           0 : tidsend(PG_FUNCTION_ARGS)
     147             : {
     148           0 :     ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
     149             :     StringInfoData buf;
     150             : 
     151           0 :     pq_begintypsend(&buf);
     152           0 :     pq_sendint(&buf, ItemPointerGetBlockNumberNoCheck(itemPtr),
     153             :                sizeof(BlockNumber));
     154           0 :     pq_sendint(&buf, ItemPointerGetOffsetNumberNoCheck(itemPtr),
     155             :                sizeof(OffsetNumber));
     156           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     157             : }
     158             : 
     159             : /*****************************************************************************
     160             :  *   PUBLIC ROUTINES                                                         *
     161             :  *****************************************************************************/
     162             : 
     163             : Datum
     164     1815030 : tideq(PG_FUNCTION_ARGS)
     165             : {
     166     1815030 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     167     1815030 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     168             : 
     169     1815030 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
     170             : }
     171             : 
     172             : Datum
     173          26 : tidne(PG_FUNCTION_ARGS)
     174             : {
     175          26 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     176          26 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     177             : 
     178          26 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
     179             : }
     180             : 
     181             : Datum
     182         510 : tidlt(PG_FUNCTION_ARGS)
     183             : {
     184         510 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     185         510 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     186             : 
     187         510 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
     188             : }
     189             : 
     190             : Datum
     191         400 : tidle(PG_FUNCTION_ARGS)
     192             : {
     193         400 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     194         400 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     195             : 
     196         400 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
     197             : }
     198             : 
     199             : Datum
     200         559 : tidgt(PG_FUNCTION_ARGS)
     201             : {
     202         559 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     203         559 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     204             : 
     205         559 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
     206             : }
     207             : 
     208             : Datum
     209         389 : tidge(PG_FUNCTION_ARGS)
     210             : {
     211         389 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     212         389 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     213             : 
     214         389 :     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
     215             : }
     216             : 
     217             : Datum
     218           9 : bttidcmp(PG_FUNCTION_ARGS)
     219             : {
     220           9 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     221           9 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     222             : 
     223           9 :     PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
     224             : }
     225             : 
     226             : Datum
     227           0 : tidlarger(PG_FUNCTION_ARGS)
     228             : {
     229           0 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     230           0 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     231             : 
     232           0 :     PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
     233             : }
     234             : 
     235             : Datum
     236           0 : tidsmaller(PG_FUNCTION_ARGS)
     237             : {
     238           0 :     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
     239           0 :     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
     240             : 
     241           0 :     PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
     242             : }
     243             : 
     244             : 
     245             : /*
     246             :  *  Functions to get latest tid of a specified tuple.
     247             :  *
     248             :  *  Maybe these implementations should be moved to another place
     249             :  */
     250             : 
     251             : static ItemPointerData Current_last_tid = {{0, 0}, 0};
     252             : 
     253             : void
     254      471895 : setLastTid(const ItemPointer tid)
     255             : {
     256      471895 :     Current_last_tid = *tid;
     257      471895 : }
     258             : 
     259             : /*
     260             :  *  Handle CTIDs of views.
     261             :  *      CTID should be defined in the view and it must
     262             :  *      correspond to the CTID of a base relation.
     263             :  */
     264             : static Datum
     265           0 : currtid_for_view(Relation viewrel, ItemPointer tid)
     266             : {
     267           0 :     TupleDesc   att = RelationGetDescr(viewrel);
     268             :     RuleLock   *rulelock;
     269             :     RewriteRule *rewrite;
     270             :     int         i,
     271           0 :                 natts = att->natts,
     272           0 :                 tididx = -1;
     273             : 
     274           0 :     for (i = 0; i < natts; i++)
     275             :     {
     276           0 :         Form_pg_attribute attr = TupleDescAttr(att, i);
     277             : 
     278           0 :         if (strcmp(NameStr(attr->attname), "ctid") == 0)
     279             :         {
     280           0 :             if (attr->atttypid != TIDOID)
     281           0 :                 elog(ERROR, "ctid isn't of type TID");
     282           0 :             tididx = i;
     283           0 :             break;
     284             :         }
     285             :     }
     286           0 :     if (tididx < 0)
     287           0 :         elog(ERROR, "currtid cannot handle views with no CTID");
     288           0 :     rulelock = viewrel->rd_rules;
     289           0 :     if (!rulelock)
     290           0 :         elog(ERROR, "the view has no rules");
     291           0 :     for (i = 0; i < rulelock->numLocks; i++)
     292             :     {
     293           0 :         rewrite = rulelock->rules[i];
     294           0 :         if (rewrite->event == CMD_SELECT)
     295             :         {
     296             :             Query      *query;
     297             :             TargetEntry *tle;
     298             : 
     299           0 :             if (list_length(rewrite->actions) != 1)
     300           0 :                 elog(ERROR, "only one select rule is allowed in views");
     301           0 :             query = (Query *) linitial(rewrite->actions);
     302           0 :             tle = get_tle_by_resno(query->targetList, tididx + 1);
     303           0 :             if (tle && tle->expr && IsA(tle->expr, Var))
     304             :             {
     305           0 :                 Var        *var = (Var *) tle->expr;
     306             :                 RangeTblEntry *rte;
     307             : 
     308           0 :                 if (!IS_SPECIAL_VARNO(var->varno) &&
     309           0 :                     var->varattno == SelfItemPointerAttributeNumber)
     310             :                 {
     311           0 :                     rte = rt_fetch(var->varno, query->rtable);
     312           0 :                     if (rte)
     313             :                     {
     314           0 :                         heap_close(viewrel, AccessShareLock);
     315           0 :                         return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
     316             :                     }
     317             :                 }
     318             :             }
     319           0 :             break;
     320             :         }
     321             :     }
     322           0 :     elog(ERROR, "currtid cannot handle this view");
     323             :     return (Datum) 0;
     324             : }
     325             : 
     326             : Datum
     327           0 : currtid_byreloid(PG_FUNCTION_ARGS)
     328             : {
     329           0 :     Oid         reloid = PG_GETARG_OID(0);
     330           0 :     ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
     331             :     ItemPointer result;
     332             :     Relation    rel;
     333             :     AclResult   aclresult;
     334             :     Snapshot    snapshot;
     335             : 
     336           0 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
     337           0 :     if (!reloid)
     338             :     {
     339           0 :         *result = Current_last_tid;
     340           0 :         PG_RETURN_ITEMPOINTER(result);
     341             :     }
     342             : 
     343           0 :     rel = heap_open(reloid, AccessShareLock);
     344             : 
     345           0 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     346             :                                   ACL_SELECT);
     347           0 :     if (aclresult != ACLCHECK_OK)
     348           0 :         aclcheck_error(aclresult, ACL_KIND_CLASS,
     349           0 :                        RelationGetRelationName(rel));
     350             : 
     351           0 :     if (rel->rd_rel->relkind == RELKIND_VIEW)
     352           0 :         return currtid_for_view(rel, tid);
     353             : 
     354           0 :     ItemPointerCopy(tid, result);
     355             : 
     356           0 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
     357           0 :     heap_get_latest_tid(rel, snapshot, result);
     358           0 :     UnregisterSnapshot(snapshot);
     359             : 
     360           0 :     heap_close(rel, AccessShareLock);
     361             : 
     362           0 :     PG_RETURN_ITEMPOINTER(result);
     363             : }
     364             : 
     365             : Datum
     366           0 : currtid_byrelname(PG_FUNCTION_ARGS)
     367             : {
     368           0 :     text       *relname = PG_GETARG_TEXT_PP(0);
     369           0 :     ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
     370             :     ItemPointer result;
     371             :     RangeVar   *relrv;
     372             :     Relation    rel;
     373             :     AclResult   aclresult;
     374             :     Snapshot    snapshot;
     375             : 
     376           0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
     377           0 :     rel = heap_openrv(relrv, AccessShareLock);
     378             : 
     379           0 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     380             :                                   ACL_SELECT);
     381           0 :     if (aclresult != ACLCHECK_OK)
     382           0 :         aclcheck_error(aclresult, ACL_KIND_CLASS,
     383           0 :                        RelationGetRelationName(rel));
     384             : 
     385           0 :     if (rel->rd_rel->relkind == RELKIND_VIEW)
     386           0 :         return currtid_for_view(rel, tid);
     387             : 
     388           0 :     result = (ItemPointer) palloc(sizeof(ItemPointerData));
     389           0 :     ItemPointerCopy(tid, result);
     390             : 
     391           0 :     snapshot = RegisterSnapshot(GetLatestSnapshot());
     392           0 :     heap_get_latest_tid(rel, snapshot, result);
     393           0 :     UnregisterSnapshot(snapshot);
     394             : 
     395           0 :     heap_close(rel, AccessShareLock);
     396             : 
     397           0 :     PG_RETURN_ITEMPOINTER(result);
     398             : }

Generated by: LCOV version 1.11