1 /*-------------------------------------------------------------------------
4 * Functions for the built-in type tuple id
6 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/tid.c
14 * input routine largely stolen from boxin().
16 *-------------------------------------------------------------------------
23 #include "access/heapam.h"
24 #include "access/sysattr.h"
25 #include "catalog/namespace.h"
26 #include "catalog/pg_type.h"
27 #include "libpq/pqformat.h"
28 #include "miscadmin.h"
29 #include "parser/parsetree.h"
30 #include "utils/acl.h"
31 #include "utils/builtins.h"
32 #include "utils/rel.h"
33 #include "utils/tqual.h"
36 #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
37 #define ItemPointerGetDatum(X) PointerGetDatum(X)
38 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
39 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
46 /* ----------------------------------------------------------------
48 * ----------------------------------------------------------------
51 tidin(PG_FUNCTION_ARGS)
53 char *str = PG_GETARG_CSTRING(0);
58 BlockNumber blockNumber;
59 OffsetNumber offsetNumber;
63 for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
64 if (*p == DELIM || (*p == LDELIM && !i))
69 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
70 errmsg("invalid input syntax for type tid: \"%s\"",
74 blockNumber = strtoul(coord[0], &badp, 10);
75 if (errno || *badp != DELIM)
77 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
78 errmsg("invalid input syntax for type tid: \"%s\"",
81 hold_offset = strtol(coord[1], &badp, 10);
82 if (errno || *badp != RDELIM ||
83 hold_offset > USHRT_MAX || hold_offset < 0)
85 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86 errmsg("invalid input syntax for type tid: \"%s\"",
89 offsetNumber = hold_offset;
91 result = (ItemPointer) palloc(sizeof(ItemPointerData));
93 ItemPointerSet(result, blockNumber, offsetNumber);
95 PG_RETURN_ITEMPOINTER(result);
98 /* ----------------------------------------------------------------
100 * ----------------------------------------------------------------
103 tidout(PG_FUNCTION_ARGS)
105 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
106 BlockNumber blockNumber;
107 OffsetNumber offsetNumber;
110 blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
111 offsetNumber = itemPtr->ip_posid;
113 /* Perhaps someday we should output this as a record. */
114 snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
116 PG_RETURN_CSTRING(pstrdup(buf));
120 * tidrecv - converts external binary format to tid
123 tidrecv(PG_FUNCTION_ARGS)
125 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
127 BlockNumber blockNumber;
128 OffsetNumber offsetNumber;
130 blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
131 offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
133 result = (ItemPointer) palloc(sizeof(ItemPointerData));
135 ItemPointerSet(result, blockNumber, offsetNumber);
137 PG_RETURN_ITEMPOINTER(result);
141 * tidsend - converts tid to binary format
144 tidsend(PG_FUNCTION_ARGS)
146 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
148 BlockNumber blockNumber;
149 OffsetNumber offsetNumber;
152 blockId = &(itemPtr->ip_blkid);
153 blockNumber = BlockIdGetBlockNumber(blockId);
154 offsetNumber = itemPtr->ip_posid;
156 pq_begintypsend(&buf);
157 pq_sendint(&buf, blockNumber, sizeof(blockNumber));
158 pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
159 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
162 /*****************************************************************************
164 *****************************************************************************/
167 tideq(PG_FUNCTION_ARGS)
169 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
170 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
172 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
176 tidne(PG_FUNCTION_ARGS)
178 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
179 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
181 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
185 tidlt(PG_FUNCTION_ARGS)
187 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
188 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
190 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
194 tidle(PG_FUNCTION_ARGS)
196 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
197 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
199 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
203 tidgt(PG_FUNCTION_ARGS)
205 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
206 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
208 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
212 tidge(PG_FUNCTION_ARGS)
214 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
215 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
217 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
221 bttidcmp(PG_FUNCTION_ARGS)
223 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
224 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
226 PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
230 tidlarger(PG_FUNCTION_ARGS)
232 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
233 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
235 PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
239 tidsmaller(PG_FUNCTION_ARGS)
241 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
242 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
244 PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
249 * Functions to get latest tid of a specified tuple.
251 * Maybe these implementations should be moved to another place
254 static ItemPointerData Current_last_tid = {{0, 0}, 0};
257 setLastTid(const ItemPointer tid)
259 Current_last_tid = *tid;
263 * Handle CTIDs of views.
264 * CTID should be defined in the view and it must
265 * correspond to the CTID of a base relation.
268 currtid_for_view(Relation viewrel, ItemPointer tid)
270 TupleDesc att = RelationGetDescr(viewrel);
272 RewriteRule *rewrite;
277 for (i = 0; i < natts; i++)
279 if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
281 if (att->attrs[i]->atttypid != TIDOID)
282 elog(ERROR, "ctid isn't of type TID");
288 elog(ERROR, "currtid cannot handle views with no CTID");
289 rulelock = viewrel->rd_rules;
291 elog(ERROR, "the view has no rules");
292 for (i = 0; i < rulelock->numLocks; i++)
294 rewrite = rulelock->rules[i];
295 if (rewrite->event == CMD_SELECT)
300 if (list_length(rewrite->actions) != 1)
301 elog(ERROR, "only one select rule is allowed in views");
302 query = (Query *) linitial(rewrite->actions);
303 tle = get_tle_by_resno(query->targetList, tididx + 1);
304 if (tle && tle->expr && IsA(tle->expr, Var))
306 Var *var = (Var *) tle->expr;
309 if (!IS_SPECIAL_VARNO(var->varno) &&
310 var->varattno == SelfItemPointerAttributeNumber)
312 rte = rt_fetch(var->varno, query->rtable);
315 heap_close(viewrel, AccessShareLock);
316 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
323 elog(ERROR, "currtid cannot handle this view");
328 currtid_byreloid(PG_FUNCTION_ARGS)
330 Oid reloid = PG_GETARG_OID(0);
331 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
336 result = (ItemPointer) palloc(sizeof(ItemPointerData));
339 *result = Current_last_tid;
340 PG_RETURN_ITEMPOINTER(result);
343 rel = heap_open(reloid, AccessShareLock);
345 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
347 if (aclresult != ACLCHECK_OK)
348 aclcheck_error(aclresult, ACL_KIND_CLASS,
349 RelationGetRelationName(rel));
351 if (rel->rd_rel->relkind == RELKIND_VIEW)
352 return currtid_for_view(rel, tid);
354 ItemPointerCopy(tid, result);
355 heap_get_latest_tid(rel, SnapshotNow, result);
357 heap_close(rel, AccessShareLock);
359 PG_RETURN_ITEMPOINTER(result);
363 currtid_byrelname(PG_FUNCTION_ARGS)
365 text *relname = PG_GETARG_TEXT_P(0);
366 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
372 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
373 rel = heap_openrv(relrv, AccessShareLock);
375 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
377 if (aclresult != ACLCHECK_OK)
378 aclcheck_error(aclresult, ACL_KIND_CLASS,
379 RelationGetRelationName(rel));
381 if (rel->rd_rel->relkind == RELKIND_VIEW)
382 return currtid_for_view(rel, tid);
384 result = (ItemPointer) palloc(sizeof(ItemPointerData));
385 ItemPointerCopy(tid, result);
387 heap_get_latest_tid(rel, SnapshotNow, result);
389 heap_close(rel, AccessShareLock);
391 PG_RETURN_ITEMPOINTER(result);