]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/tid.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / tid.c
index 4385b003deb1a5afff6008f4d0b32ab68368e3bb..49a5a157b94e24b5781c0f9bb6cb09c56c03891a 100644 (file)
@@ -3,23 +3,37 @@
  * tid.c
  *       Functions for the built-in type tuple id
  *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.27 2001/09/17 00:29:10 tgl Exp $
+ *       src/backend/utils/adt/tid.c
  *
  * NOTES
  *       input routine largely stolen from boxin().
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
 
+#include <math.h>
+#include <limits.h>
+
 #include "access/heapam.h"
+#include "access/sysattr.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_type.h"
+#include "libpq/pqformat.h"
+#include "miscadmin.h"
+#include "parser/parsetree.h"
+#include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/rel.h"
+#include "utils/snapmgr.h"
+#include "utils/tqual.h"
+#include "utils/varlena.h"
+
 
 #define DatumGetItemPointer(X)  ((ItemPointer) DatumGetPointer(X))
 #define ItemPointerGetDatum(X)  PointerGetDatum(X)
@@ -45,16 +59,36 @@ tidin(PG_FUNCTION_ARGS)
        ItemPointer result;
        BlockNumber blockNumber;
        OffsetNumber offsetNumber;
+       char       *badp;
+       int                     hold_offset;
 
        for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
                if (*p == DELIM || (*p == LDELIM && !i))
                        coord[i++] = p + 1;
 
        if (i < NTIDARGS)
-               elog(ERROR, "invalid tid format: '%s'", str);
-
-       blockNumber = (BlockNumber) atoi(coord[0]);
-       offsetNumber = (OffsetNumber) atoi(coord[1]);
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+                                errmsg("invalid input syntax for type %s: \"%s\"",
+                                               "tid", str)));
+
+       errno = 0;
+       blockNumber = strtoul(coord[0], &badp, 10);
+       if (errno || *badp != DELIM)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+                                errmsg("invalid input syntax for type %s: \"%s\"",
+                                               "tid", str)));
+
+       hold_offset = strtol(coord[1], &badp, 10);
+       if (errno || *badp != RDELIM ||
+               hold_offset > USHRT_MAX || hold_offset < 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+                                errmsg("invalid input syntax for type %s: \"%s\"",
+                                               "tid", str)));
+
+       offsetNumber = hold_offset;
 
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
 
@@ -71,23 +105,60 @@ Datum
 tidout(PG_FUNCTION_ARGS)
 {
        ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
-       BlockId         blockId;
        BlockNumber blockNumber;
        OffsetNumber offsetNumber;
        char            buf[32];
-       static char *invalidTid = "()";
 
-       if (!ItemPointerIsValid(itemPtr))
-               PG_RETURN_CSTRING(pstrdup(invalidTid));
+       blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
+       offsetNumber = itemPtr->ip_posid;
 
-       blockId = &(itemPtr->ip_blkid);
+       /* Perhaps someday we should output this as a record. */
+       snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
+
+       PG_RETURN_CSTRING(pstrdup(buf));
+}
+
+/*
+ *             tidrecv                 - converts external binary format to tid
+ */
+Datum
+tidrecv(PG_FUNCTION_ARGS)
+{
+       StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
+       ItemPointer result;
+       BlockNumber blockNumber;
+       OffsetNumber offsetNumber;
+
+       blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
+       offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
+
+       result = (ItemPointer) palloc(sizeof(ItemPointerData));
 
+       ItemPointerSet(result, blockNumber, offsetNumber);
+
+       PG_RETURN_ITEMPOINTER(result);
+}
+
+/*
+ *             tidsend                 - converts tid to binary format
+ */
+Datum
+tidsend(PG_FUNCTION_ARGS)
+{
+       ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
+       BlockId         blockId;
+       BlockNumber blockNumber;
+       OffsetNumber offsetNumber;
+       StringInfoData buf;
+
+       blockId = &(itemPtr->ip_blkid);
        blockNumber = BlockIdGetBlockNumber(blockId);
        offsetNumber = itemPtr->ip_posid;
 
-       sprintf(buf, "(%d,%d)", (int) blockNumber, (int) offsetNumber);
-
-       PG_RETURN_CSTRING(pstrdup(buf));
+       pq_begintypsend(&buf);
+       pq_sendint(&buf, blockNumber, sizeof(blockNumber));
+       pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
+       PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 /*****************************************************************************
@@ -100,24 +171,81 @@ tideq(PG_FUNCTION_ARGS)
        ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
        ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
 
-       PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
-                                  BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
-                                  arg1->ip_posid == arg2->ip_posid);
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
 }
 
-#ifdef NOT_USED
 Datum
 tidne(PG_FUNCTION_ARGS)
 {
        ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
        ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
 
-       PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
-                                  BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
-                                  arg1->ip_posid != arg2->ip_posid);
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
+}
+
+Datum
+tidlt(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
+}
+
+Datum
+tidle(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
+}
+
+Datum
+tidgt(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
+}
+
+Datum
+tidge(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
+}
+
+Datum
+bttidcmp(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
+}
+
+Datum
+tidlarger(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
+}
+
+Datum
+tidsmaller(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
 }
 
-#endif
 
 /*
  *     Functions to get latest tid of a specified tuple.
@@ -125,7 +253,7 @@ tidne(PG_FUNCTION_ARGS)
  *     Maybe these implementations should be moved to another place
  */
 
-static ItemPointerData Current_last_tid = { {0, 0}, 0};
+static ItemPointerData Current_last_tid = {{0, 0}, 0};
 
 void
 setLastTid(const ItemPointer tid)
@@ -133,6 +261,71 @@ setLastTid(const ItemPointer tid)
        Current_last_tid = *tid;
 }
 
+/*
+ *     Handle CTIDs of views.
+ *             CTID should be defined in the view and it must
+ *             correspond to the CTID of a base relation.
+ */
+static Datum
+currtid_for_view(Relation viewrel, ItemPointer tid)
+{
+       TupleDesc       att = RelationGetDescr(viewrel);
+       RuleLock   *rulelock;
+       RewriteRule *rewrite;
+       int                     i,
+                               natts = att->natts,
+                               tididx = -1;
+
+       for (i = 0; i < natts; i++)
+       {
+               if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
+               {
+                       if (att->attrs[i]->atttypid != TIDOID)
+                               elog(ERROR, "ctid isn't of type TID");
+                       tididx = i;
+                       break;
+               }
+       }
+       if (tididx < 0)
+               elog(ERROR, "currtid cannot handle views with no CTID");
+       rulelock = viewrel->rd_rules;
+       if (!rulelock)
+               elog(ERROR, "the view has no rules");
+       for (i = 0; i < rulelock->numLocks; i++)
+       {
+               rewrite = rulelock->rules[i];
+               if (rewrite->event == CMD_SELECT)
+               {
+                       Query      *query;
+                       TargetEntry *tle;
+
+                       if (list_length(rewrite->actions) != 1)
+                               elog(ERROR, "only one select rule is allowed in views");
+                       query = (Query *) linitial(rewrite->actions);
+                       tle = get_tle_by_resno(query->targetList, tididx + 1);
+                       if (tle && tle->expr && IsA(tle->expr, Var))
+                       {
+                               Var                *var = (Var *) tle->expr;
+                               RangeTblEntry *rte;
+
+                               if (!IS_SPECIAL_VARNO(var->varno) &&
+                                       var->varattno == SelfItemPointerAttributeNumber)
+                               {
+                                       rte = rt_fetch(var->varno, query->rtable);
+                                       if (rte)
+                                       {
+                                               heap_close(viewrel, AccessShareLock);
+                                               return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
+                                       }
+                               }
+                       }
+                       break;
+               }
+       }
+       elog(ERROR, "currtid cannot handle this view");
+       return (Datum) 0;
+}
+
 Datum
 currtid_byreloid(PG_FUNCTION_ARGS)
 {
@@ -140,21 +333,34 @@ currtid_byreloid(PG_FUNCTION_ARGS)
        ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
        ItemPointer result;
        Relation        rel;
+       AclResult       aclresult;
+       Snapshot        snapshot;
 
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
-       if (!reloid) 
-       { 
-               *result = Current_last_tid; 
-               PG_RETURN_ITEMPOINTER(result); 
-       } 
-       ItemPointerCopy(tid, result);
-       if ((rel = heap_open(reloid, AccessShareLock)) != NULL)
+       if (!reloid)
        {
-               heap_get_latest_tid(rel, SnapshotNow, result);
-               heap_close(rel, AccessShareLock);
+               *result = Current_last_tid;
+               PG_RETURN_ITEMPOINTER(result);
        }
-       else
-               elog(ERROR, "Relation %u not found", reloid);
+
+       rel = heap_open(reloid, AccessShareLock);
+
+       aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+                                                                 ACL_SELECT);
+       if (aclresult != ACLCHECK_OK)
+               aclcheck_error(aclresult, ACL_KIND_CLASS,
+                                          RelationGetRelationName(rel));
+
+       if (rel->rd_rel->relkind == RELKIND_VIEW)
+               return currtid_for_view(rel, tid);
+
+       ItemPointerCopy(tid, result);
+
+       snapshot = RegisterSnapshot(GetLatestSnapshot());
+       heap_get_latest_tid(rel, snapshot, result);
+       UnregisterSnapshot(snapshot);
+
+       heap_close(rel, AccessShareLock);
 
        PG_RETURN_ITEMPOINTER(result);
 }
@@ -162,26 +368,34 @@ currtid_byreloid(PG_FUNCTION_ARGS)
 Datum
 currtid_byrelname(PG_FUNCTION_ARGS)
 {
-       text       *relname = PG_GETARG_TEXT_P(0);
+       text       *relname = PG_GETARG_TEXT_PP(0);
        ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
        ItemPointer result;
-       char       *str;
+       RangeVar   *relrv;
        Relation        rel;
+       AclResult       aclresult;
+       Snapshot        snapshot;
+
+       relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
+       rel = heap_openrv(relrv, AccessShareLock);
+
+       aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+                                                                 ACL_SELECT);
+       if (aclresult != ACLCHECK_OK)
+               aclcheck_error(aclresult, ACL_KIND_CLASS,
+                                          RelationGetRelationName(rel));
 
-       str = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                         PointerGetDatum(relname)));
+       if (rel->rd_rel->relkind == RELKIND_VIEW)
+               return currtid_for_view(rel, tid);
 
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
        ItemPointerCopy(tid, result);
-       if ((rel = heap_openr(str, AccessShareLock)) != NULL)
-       {
-               heap_get_latest_tid(rel, SnapshotNow, result);
-               heap_close(rel, AccessShareLock);
-       }
-       else
-               elog(ERROR, "Relation %s not found", str);
 
-       pfree(str);
+       snapshot = RegisterSnapshot(GetLatestSnapshot());
+       heap_get_latest_tid(rel, snapshot, result);
+       UnregisterSnapshot(snapshot);
+
+       heap_close(rel, AccessShareLock);
 
        PG_RETURN_ITEMPOINTER(result);
 }