1 /*-------------------------------------------------------------------------
4 * Functions for the built-in type tuple id
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/utils/adt/tid.c,v 1.51 2006/02/27 01:41:16 momjian Exp $
14 * input routine largely stolen from boxin().
16 *-------------------------------------------------------------------------
24 #include "access/heapam.h"
25 #include "catalog/namespace.h"
26 #include "catalog/pg_type.h"
27 #include "libpq/pqformat.h"
28 #include "parser/parsetree.h"
29 #include "utils/builtins.h"
32 #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
33 #define ItemPointerGetDatum(X) PointerGetDatum(X)
34 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
35 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
42 /* ----------------------------------------------------------------
44 * ----------------------------------------------------------------
47 tidin(PG_FUNCTION_ARGS)
49 char *str = PG_GETARG_CSTRING(0);
54 BlockNumber blockNumber;
55 OffsetNumber offsetNumber;
59 for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
60 if (*p == DELIM || (*p == LDELIM && !i))
65 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
66 errmsg("invalid input syntax for type tid: \"%s\"",
70 blockNumber = strtoul(coord[0], &badp, 10);
71 if (errno || *badp != DELIM)
73 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
74 errmsg("invalid input syntax for type tid: \"%s\"",
77 hold_offset = strtol(coord[1], &badp, 10);
78 if (errno || *badp != RDELIM ||
79 hold_offset > USHRT_MAX || hold_offset < 0)
81 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
82 errmsg("invalid input syntax for type tid: \"%s\"",
85 offsetNumber = hold_offset;
87 result = (ItemPointer) palloc(sizeof(ItemPointerData));
89 ItemPointerSet(result, blockNumber, offsetNumber);
91 PG_RETURN_ITEMPOINTER(result);
94 /* ----------------------------------------------------------------
96 * ----------------------------------------------------------------
99 tidout(PG_FUNCTION_ARGS)
101 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
103 BlockNumber blockNumber;
104 OffsetNumber offsetNumber;
107 if (!ItemPointerIsValid(itemPtr))
108 PG_RETURN_CSTRING(pstrdup("()"));
110 blockId = &(itemPtr->ip_blkid);
111 blockNumber = BlockIdGetBlockNumber(blockId);
112 offsetNumber = itemPtr->ip_posid;
114 /* Perhaps someday we should output this as a record. */
115 snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
117 PG_RETURN_CSTRING(pstrdup(buf));
121 * tidrecv - converts external binary format to tid
124 tidrecv(PG_FUNCTION_ARGS)
126 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
128 BlockNumber blockNumber;
129 OffsetNumber offsetNumber;
131 blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
132 offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
134 result = (ItemPointer) palloc(sizeof(ItemPointerData));
136 ItemPointerSet(result, blockNumber, offsetNumber);
138 PG_RETURN_ITEMPOINTER(result);
142 * tidsend - converts tid to binary format
145 tidsend(PG_FUNCTION_ARGS)
147 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
149 BlockNumber blockNumber;
150 OffsetNumber offsetNumber;
153 blockId = &(itemPtr->ip_blkid);
154 blockNumber = BlockIdGetBlockNumber(blockId);
155 offsetNumber = itemPtr->ip_posid;
157 pq_begintypsend(&buf);
158 pq_sendint(&buf, blockNumber, sizeof(blockNumber));
159 pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
160 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
163 /*****************************************************************************
165 *****************************************************************************/
168 tideq(PG_FUNCTION_ARGS)
170 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
171 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
173 PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
174 BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
175 arg1->ip_posid == arg2->ip_posid);
179 tidne(PG_FUNCTION_ARGS)
181 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
182 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
184 PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
185 BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
186 arg1->ip_posid != arg2->ip_posid);
190 * Functions to get latest tid of a specified tuple.
192 * Maybe these implementations should be moved to another place
195 static ItemPointerData Current_last_tid = {{0, 0}, 0};
198 setLastTid(const ItemPointer tid)
200 Current_last_tid = *tid;
204 * Handle CTIDs of views.
205 * CTID should be defined in the view and it must
206 * correspond to the CTID of a base relation.
209 currtid_for_view(Relation viewrel, ItemPointer tid)
211 TupleDesc att = RelationGetDescr(viewrel);
213 RewriteRule *rewrite;
218 for (i = 0; i < natts; i++)
220 if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
222 if (att->attrs[i]->atttypid != TIDOID)
223 elog(ERROR, "ctid isn't of type TID");
229 elog(ERROR, "currtid cannot handle views with no CTID");
230 rulelock = viewrel->rd_rules;
232 elog(ERROR, "the view has no rules");
233 for (i = 0; i < rulelock->numLocks; i++)
235 rewrite = rulelock->rules[i];
236 if (rewrite->event == CMD_SELECT)
241 if (list_length(rewrite->actions) != 1)
242 elog(ERROR, "only one select rule is allowed in views");
243 query = (Query *) linitial(rewrite->actions);
244 tle = get_tle_by_resno(query->targetList, tididx + 1);
245 if (tle && tle->expr && IsA(tle->expr, Var))
247 Var *var = (Var *) tle->expr;
250 if (var->varno > 0 && var->varno < INNER &&
251 var->varattno == SelfItemPointerAttributeNumber)
253 rte = rt_fetch(var->varno, query->rtable);
256 heap_close(viewrel, AccessShareLock);
257 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
264 elog(ERROR, "currtid cannot handle this view");
269 currtid_byreloid(PG_FUNCTION_ARGS)
271 Oid reloid = PG_GETARG_OID(0);
272 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
276 result = (ItemPointer) palloc(sizeof(ItemPointerData));
279 *result = Current_last_tid;
280 PG_RETURN_ITEMPOINTER(result);
283 rel = heap_open(reloid, AccessShareLock);
284 if (rel->rd_rel->relkind == RELKIND_VIEW)
285 return currtid_for_view(rel, tid);
287 ItemPointerCopy(tid, result);
288 heap_get_latest_tid(rel, SnapshotNow, result);
290 heap_close(rel, AccessShareLock);
292 PG_RETURN_ITEMPOINTER(result);
296 currtid_byrelname(PG_FUNCTION_ARGS)
298 text *relname = PG_GETARG_TEXT_P(0);
299 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
304 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
305 rel = heap_openrv(relrv, AccessShareLock);
306 if (rel->rd_rel->relkind == RELKIND_VIEW)
307 return currtid_for_view(rel, tid);
309 result = (ItemPointer) palloc(sizeof(ItemPointerData));
310 ItemPointerCopy(tid, result);
312 heap_get_latest_tid(rel, SnapshotNow, result);
314 heap_close(rel, AccessShareLock);
316 PG_RETURN_ITEMPOINTER(result);