]> 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 263470a063cf54a675bbc41fb947181228fdb9cd..49a5a157b94e24b5781c0f9bb6cb09c56c03891a 100644 (file)
@@ -3,23 +3,42 @@
  * tid.c
  *       Functions for the built-in type tuple id
  *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * 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.20 2000/06/09 01:11:09 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)
+#define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
+#define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
 
 #define LDELIM                 '('
 #define RDELIM                 ')'
  *             tidin
  * ----------------------------------------------------------------
  */
-ItemPointer
-tidin(const char *str)
+Datum
+tidin(PG_FUNCTION_ARGS)
 {
-       const char *p,
+       char       *str = PG_GETARG_CSTRING(0);
+       char       *p,
                           *coord[NTIDARGS];
        int                     i;
        ItemPointer result;
-
        BlockNumber blockNumber;
        OffsetNumber offsetNumber;
-
-       if (str == NULL)
-               return NULL;
+       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 - 1) */
        if (i < NTIDARGS)
-       {
-               elog(ERROR, "%s invalid tid format", str);
-               return NULL;
-       }
-
-       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));
 
        ItemPointerSet(result, blockNumber, offsetNumber);
 
-       return result;
+       PG_RETURN_ITEMPOINTER(result);
 }
 
 /* ----------------------------------------------------------------
  *             tidout
  * ----------------------------------------------------------------
  */
-char *
-tidout(ItemPointer itemPtr)
+Datum
+tidout(PG_FUNCTION_ARGS)
 {
+       ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
        BlockNumber blockNumber;
        OffsetNumber offsetNumber;
-       BlockId         blockId;
        char            buf[32];
-       char       *str;
-       static char *invalidTid = "()";
 
-       if (!itemPtr || !ItemPointerIsValid(itemPtr))
-       {
-               str = palloc(strlen(invalidTid));
-               strcpy(str, invalidTid);
-               return str;
-       }
+       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);
 
-       blockNumber = BlockIdGetBlockNumber(blockId);
-       offsetNumber = itemPtr->ip_posid;
+       PG_RETURN_CSTRING(pstrdup(buf));
+}
 
-       sprintf(buf, "(%d,%d)", blockNumber, offsetNumber);
+/*
+ *             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;
 
-       str = (char *) palloc(strlen(buf) + 1);
-       strcpy(str, buf);
+       blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
+       offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
 
-       return str;
+       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;
+
+       pq_begintypsend(&buf);
+       pq_sendint(&buf, blockNumber, sizeof(blockNumber));
+       pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
+       PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
 /*****************************************************************************
  *      PUBLIC ROUTINES                                                                                                                 *
  *****************************************************************************/
 
-bool
-tideq(ItemPointer arg1, ItemPointer arg2)
+Datum
+tideq(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
+}
+
+Datum
+tidne(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
+}
+
+Datum
+tidlt(PG_FUNCTION_ARGS)
 {
-       if ((!arg1) || (!arg2))
-               return false;
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
 
-       return (BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
-                       BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
-                       arg1->ip_posid == arg2->ip_posid);
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
 }
 
-#ifdef NOT_USED
-bool
-tidne(ItemPointer arg1, ItemPointer arg2)
+Datum
+tidle(PG_FUNCTION_ARGS)
 {
-       if ((!arg1) || (!arg2))
-               return false;
-       return (BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
-                       BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
-                       arg1->ip_posid != arg2->ip_posid);
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
+
+       PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
 }
-#endif
 
-#ifdef NOT_USED
-text *
-tid_text(ItemPointer tid)
+Datum
+tidgt(PG_FUNCTION_ARGS)
 {
-       char       *str;
+       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);
+}
 
-       if (!tid)
-               return (text *) NULL;
-       str = tidout(tid);
+Datum
+bttidcmp(PG_FUNCTION_ARGS)
+{
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
 
-       return textin(str);
-}      /* tid_text() */
-#endif
+       PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
+}
 
-#ifdef NOT_USED
-ItemPointer
-text_tid(const text *string)
+Datum
+tidlarger(PG_FUNCTION_ARGS)
 {
-       ItemPointer result;
-       char       *str;
+       ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
+       ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
 
-       if (!string)
-               return (ItemPointer) 0;
+       PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
+}
 
-       str = textout((text *) string);
-       result = tidin(str);
-       pfree(str);
+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);
+}
 
-       return result;
-}      /* text_tid() */
-#endif
 
 /*
  *     Functions to get latest tid of a specified tuple.
  *
  *     Maybe these implementations should be moved to another place
  */
+
+static ItemPointerData Current_last_tid = {{0, 0}, 0};
+
+void
+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)
 {
-       Oid                             reloid = PG_GETARG_OID(0);
-       ItemPointer             tid = (ItemPointer) PG_GETARG_POINTER(1);
-       ItemPointer             result,
-                                       ret;
-       Relation                rel;
+       Oid                     reloid = PG_GETARG_OID(0);
+       ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
+       ItemPointer result;
+       Relation        rel;
+       AclResult       aclresult;
+       Snapshot        snapshot;
 
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
-       ItemPointerSetInvalid(result);
-       if ((rel = heap_open(reloid, AccessShareLock)) != NULL)
+       if (!reloid)
        {
-               ret = heap_get_latest_tid(rel, SnapshotNow, tid);
-               if (ret)
-                       ItemPointerCopy(ret, result);
-               heap_close(rel, AccessShareLock);
+               *result = Current_last_tid;
+               PG_RETURN_ITEMPOINTER(result);
        }
-       else
-               elog(ERROR, "Relation %u not found", reloid);
 
-       PG_RETURN_POINTER(result);
+       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);
 }
 
 Datum
 currtid_byrelname(PG_FUNCTION_ARGS)
 {
-       text               *relname = PG_GETARG_TEXT_P(0);
-       ItemPointer             tid = (ItemPointer) PG_GETARG_POINTER(1);
-       ItemPointer             result,
-                                       ret;
-       char               *str;
-       Relation                rel;
+       text       *relname = PG_GETARG_TEXT_PP(0);
+       ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
+       ItemPointer result;
+       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 = textout(relname);
+       if (rel->rd_rel->relkind == RELKIND_VIEW)
+               return currtid_for_view(rel, tid);
 
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
-       ItemPointerSetInvalid(result);
-       if ((rel = heap_openr(str, AccessShareLock)) != NULL)
-       {
-               ret = heap_get_latest_tid(rel, SnapshotNow, tid);
-               if (ret)
-                       ItemPointerCopy(ret, result);
-               heap_close(rel, AccessShareLock);
-       }
-       else
-               elog(ERROR, "Relation %s not found", str);
+       ItemPointerCopy(tid, result);
+
+       snapshot = RegisterSnapshot(GetLatestSnapshot());
+       heap_get_latest_tid(rel, snapshot, result);
+       UnregisterSnapshot(snapshot);
 
-       pfree(str);
+       heap_close(rel, AccessShareLock);
 
-       PG_RETURN_POINTER(result);
+       PG_RETURN_ITEMPOINTER(result);
 }