1 /*-------------------------------------------------------------------------
4 * Functions for the built-in type tuple id
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.32 2002/07/16 17:55:25 momjian Exp $
14 * input routine largely stolen from boxin().
16 *-------------------------------------------------------------------------
25 #include "access/heapam.h"
26 #include "catalog/namespace.h"
27 #include "utils/builtins.h"
28 #include "catalog/pg_type.h"
30 #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
31 #define ItemPointerGetDatum(X) PointerGetDatum(X)
32 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
33 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
40 /* ----------------------------------------------------------------
42 * ----------------------------------------------------------------
45 tidin(PG_FUNCTION_ARGS)
47 char *str = PG_GETARG_CSTRING(0);
52 BlockNumber blockNumber;
53 OffsetNumber offsetNumber;
57 for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
58 if (*p == DELIM || (*p == LDELIM && !i))
62 elog(ERROR, "invalid tid format: '%s'", str);
65 blockNumber = strtoul(coord[0], &badp, 10);
66 if (errno || *badp != DELIM)
67 elog(ERROR, "tidin: invalid value.");
69 hold_offset = strtol(coord[1], &badp, 10);
70 if (errno || *badp != RDELIM ||
71 hold_offset > USHRT_MAX || hold_offset < 0)
72 elog(ERROR, "tidin: invalid value.");
73 offsetNumber = hold_offset;
75 result = (ItemPointer) palloc(sizeof(ItemPointerData));
77 ItemPointerSet(result, blockNumber, offsetNumber);
79 PG_RETURN_ITEMPOINTER(result);
82 /* ----------------------------------------------------------------
84 * ----------------------------------------------------------------
87 tidout(PG_FUNCTION_ARGS)
89 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
91 BlockNumber blockNumber;
92 OffsetNumber offsetNumber;
94 static char *invalidTid = "()";
96 if (!ItemPointerIsValid(itemPtr))
97 PG_RETURN_CSTRING(pstrdup(invalidTid));
99 blockId = &(itemPtr->ip_blkid);
101 blockNumber = BlockIdGetBlockNumber(blockId);
102 offsetNumber = itemPtr->ip_posid;
104 sprintf(buf, "(%u,%u)", blockNumber, offsetNumber);
106 PG_RETURN_CSTRING(pstrdup(buf));
109 /*****************************************************************************
111 *****************************************************************************/
114 tideq(PG_FUNCTION_ARGS)
116 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
117 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
119 PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
120 BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
121 arg1->ip_posid == arg2->ip_posid);
126 tidne(PG_FUNCTION_ARGS)
128 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
129 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
131 PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
132 BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
133 arg1->ip_posid != arg2->ip_posid);
138 * Functions to get latest tid of a specified tuple.
140 * Maybe these implementations should be moved to another place
143 static ItemPointerData Current_last_tid = {{0, 0}, 0};
146 setLastTid(const ItemPointer tid)
148 Current_last_tid = *tid;
152 * Handle CTIDs of views.
153 * CTID should be defined in the view and it must
154 * correspond to the CTID of a base relation.
157 currtid_for_view(Relation viewrel, ItemPointer tid)
159 TupleDesc att = RelationGetDescr(viewrel);
161 RewriteRule *rewrite;
162 int i, natts = att->natts, tididx = -1;
164 for (i = 0; i < natts ; i++)
166 if (strcasecmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
168 if (att->attrs[i]->atttypid != TIDOID)
169 elog(ERROR, "ctid isn't of type TID");
174 elog(ERROR, "currtid can't handle views with no CTID");
175 if (rulelock = viewrel->rd_rules, !rulelock)
176 elog(ERROR, "the view has no rules");
177 for (i = 0; i < rulelock->numLocks; i++)
179 rewrite = rulelock->rules[i];
180 if (rewrite->event == CMD_SELECT)
185 if (length(rewrite->actions) != 1)
186 elog(ERROR, "only one select rule is allowed in views");
187 query = (Query *) lfirst(rewrite->actions);
188 tle = (TargetEntry *) nth(tididx, query->targetList);
189 if (tle && tle->expr && nodeTag(tle->expr) == T_Var)
191 Var *var = (Var *) tle->expr;
193 if (var->varno > 0 && var->varno < INNER && var->varattno == SelfItemPointerAttributeNumber)
195 rte = (RangeTblEntry *) nth(var->varno - 1, query->rtable);
198 heap_close(viewrel, AccessShareLock);
199 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
206 elog(ERROR, "currtid can't handle this view");
211 currtid_byreloid(PG_FUNCTION_ARGS)
213 Oid reloid = PG_GETARG_OID(0);
214 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
218 result = (ItemPointer) palloc(sizeof(ItemPointerData));
221 *result = Current_last_tid;
222 PG_RETURN_ITEMPOINTER(result);
225 rel = heap_open(reloid, AccessShareLock);
226 if (rel->rd_rel->relkind == RELKIND_VIEW)
227 return currtid_for_view(rel, tid);
229 ItemPointerCopy(tid, result);
230 heap_get_latest_tid(rel, SnapshotNow, result);
232 heap_close(rel, AccessShareLock);
234 PG_RETURN_ITEMPOINTER(result);
238 currtid_byrelname(PG_FUNCTION_ARGS)
240 text *relname = PG_GETARG_TEXT_P(0);
241 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
246 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
247 "currtid_byrelname"));
248 rel = heap_openrv(relrv, AccessShareLock);
249 if (rel->rd_rel->relkind == RELKIND_VIEW)
250 return currtid_for_view(rel, tid);
252 result = (ItemPointer) palloc(sizeof(ItemPointerData));
253 ItemPointerCopy(tid, result);
255 heap_get_latest_tid(rel, SnapshotNow, result);
257 heap_close(rel, AccessShareLock);
259 PG_RETURN_ITEMPOINTER(result);