* tid.c
* Functions for the built-in type tuple id
*
- * Portions Copyright (c) 1996-2002, 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.35 2002/08/29 00:17:05 tgl Exp $
+ * src/backend/utils/adt/tid.c
*
* NOTES
* input routine largely stolen from boxin().
*
*-------------------------------------------------------------------------
*/
-
#include "postgres.h"
-#include <errno.h>
#include <math.h>
#include <limits.h>
#include "access/heapam.h"
+#include "access/sysattr.h"
#include "catalog/namespace.h"
-#include "utils/builtins.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)
coord[i++] = p + 1;
if (i < NTIDARGS)
- elog(ERROR, "invalid tid format: '%s'", str);
+ 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)
- elog(ERROR, "tidin: invalid value.");
+ 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)
- elog(ERROR, "tidin: invalid value.");
+ 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));
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));
- blockId = &(itemPtr->ip_blkid);
-
- blockNumber = BlockIdGetBlockNumber(blockId);
+ blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
offsetNumber = itemPtr->ip_posid;
+ /* 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;
+
+ pq_begintypsend(&buf);
+ pq_sendint(&buf, blockNumber, sizeof(blockNumber));
+ pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
+ PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
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);
}
-#endif
+
+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);
+}
+
/*
* Functions to get latest tid of a specified tuple.
* correspond to the CTID of a base relation.
*/
static Datum
-currtid_for_view(Relation viewrel, ItemPointer tid)
+currtid_for_view(Relation viewrel, ItemPointer tid)
{
TupleDesc att = RelationGetDescr(viewrel);
- RuleLock *rulelock;
- RewriteRule *rewrite;
- int i, natts = att->natts, tididx = -1;
+ RuleLock *rulelock;
+ RewriteRule *rewrite;
+ int i,
+ natts = att->natts,
+ tididx = -1;
- for (i = 0; i < natts ; i++)
+ for (i = 0; i < natts; i++)
{
- if (strcasecmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
+ 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 can't handle views with no CTID");
- if (rulelock = viewrel->rd_rules, !rulelock)
+ 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;
+ Query *query;
TargetEntry *tle;
- if (length(rewrite->actions) != 1)
+ if (list_length(rewrite->actions) != 1)
elog(ERROR, "only one select rule is allowed in views");
- query = (Query *) lfirst(rewrite->actions);
- tle = (TargetEntry *) nth(tididx, query->targetList);
- if (tle && tle->expr && nodeTag(tle->expr) == T_Var)
+ 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;
+ Var *var = (Var *) tle->expr;
RangeTblEntry *rte;
- if (var->varno > 0 && var->varno < INNER && var->varattno == SelfItemPointerAttributeNumber)
+
+ if (!IS_SPECIAL_VARNO(var->varno) &&
+ var->varattno == SelfItemPointerAttributeNumber)
{
- rte = (RangeTblEntry *) nth(var->varno - 1, query->rtable);
+ rte = rt_fetch(var->varno, query->rtable);
if (rte)
{
heap_close(viewrel, AccessShareLock);
break;
}
}
- elog(ERROR, "currtid can't handle this view");
+ elog(ERROR, "currtid cannot handle this view");
return (Datum) 0;
}
ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
ItemPointer result;
Relation rel;
+ AclResult aclresult;
+ Snapshot snapshot;
result = (ItemPointer) palloc(sizeof(ItemPointerData));
if (!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);
- heap_get_latest_tid(rel, SnapshotNow, result);
+
+ snapshot = RegisterSnapshot(GetLatestSnapshot());
+ heap_get_latest_tid(rel, snapshot, result);
+ UnregisterSnapshot(snapshot);
heap_close(rel, AccessShareLock);
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;
RangeVar *relrv;
Relation rel;
+ AclResult aclresult;
+ Snapshot snapshot;
- relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
- "currtid_byrelname"));
+ 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));
+
if (rel->rd_rel->relkind == RELKIND_VIEW)
return currtid_for_view(rel, tid);
result = (ItemPointer) palloc(sizeof(ItemPointerData));
ItemPointerCopy(tid, result);
- heap_get_latest_tid(rel, SnapshotNow, result);
+ snapshot = RegisterSnapshot(GetLatestSnapshot());
+ heap_get_latest_tid(rel, snapshot, result);
+ UnregisterSnapshot(snapshot);
heap_close(rel, AccessShareLock);