1 /*-------------------------------------------------------------------------
4 * Functions for the built-in type tuple id
6 * Portions Copyright (c) 1996-2017, 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/snapmgr.h"
34 #include "utils/tqual.h"
35 #include "utils/varlena.h"
38 #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
39 #define ItemPointerGetDatum(X) PointerGetDatum(X)
40 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
41 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
48 /* ----------------------------------------------------------------
50 * ----------------------------------------------------------------
53 tidin(PG_FUNCTION_ARGS)
55 char *str = PG_GETARG_CSTRING(0);
60 BlockNumber blockNumber;
61 OffsetNumber offsetNumber;
65 for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
66 if (*p == DELIM || (*p == LDELIM && !i))
71 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
72 errmsg("invalid input syntax for type %s: \"%s\"",
76 blockNumber = strtoul(coord[0], &badp, 10);
77 if (errno || *badp != DELIM)
79 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
80 errmsg("invalid input syntax for type %s: \"%s\"",
83 hold_offset = strtol(coord[1], &badp, 10);
84 if (errno || *badp != RDELIM ||
85 hold_offset > USHRT_MAX || hold_offset < 0)
87 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
88 errmsg("invalid input syntax for type %s: \"%s\"",
91 offsetNumber = hold_offset;
93 result = (ItemPointer) palloc(sizeof(ItemPointerData));
95 ItemPointerSet(result, blockNumber, offsetNumber);
97 PG_RETURN_ITEMPOINTER(result);
100 /* ----------------------------------------------------------------
102 * ----------------------------------------------------------------
105 tidout(PG_FUNCTION_ARGS)
107 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
108 BlockNumber blockNumber;
109 OffsetNumber offsetNumber;
112 blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
113 offsetNumber = itemPtr->ip_posid;
115 /* Perhaps someday we should output this as a record. */
116 snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
118 PG_RETURN_CSTRING(pstrdup(buf));
122 * tidrecv - converts external binary format to tid
125 tidrecv(PG_FUNCTION_ARGS)
127 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
129 BlockNumber blockNumber;
130 OffsetNumber offsetNumber;
132 blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
133 offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
135 result = (ItemPointer) palloc(sizeof(ItemPointerData));
137 ItemPointerSet(result, blockNumber, offsetNumber);
139 PG_RETURN_ITEMPOINTER(result);
143 * tidsend - converts tid to binary format
146 tidsend(PG_FUNCTION_ARGS)
148 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
150 BlockNumber blockNumber;
151 OffsetNumber offsetNumber;
154 blockId = &(itemPtr->ip_blkid);
155 blockNumber = BlockIdGetBlockNumber(blockId);
156 offsetNumber = itemPtr->ip_posid;
158 pq_begintypsend(&buf);
159 pq_sendint(&buf, blockNumber, sizeof(blockNumber));
160 pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
161 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
164 /*****************************************************************************
166 *****************************************************************************/
169 tideq(PG_FUNCTION_ARGS)
171 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
172 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
174 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
178 tidne(PG_FUNCTION_ARGS)
180 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
181 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
183 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
187 tidlt(PG_FUNCTION_ARGS)
189 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
190 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
192 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
196 tidle(PG_FUNCTION_ARGS)
198 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
199 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
201 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
205 tidgt(PG_FUNCTION_ARGS)
207 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
208 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
210 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
214 tidge(PG_FUNCTION_ARGS)
216 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
217 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
219 PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
223 bttidcmp(PG_FUNCTION_ARGS)
225 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
226 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
228 PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
232 tidlarger(PG_FUNCTION_ARGS)
234 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
235 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
237 PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
241 tidsmaller(PG_FUNCTION_ARGS)
243 ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
244 ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
246 PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
251 * Functions to get latest tid of a specified tuple.
253 * Maybe these implementations should be moved to another place
256 static ItemPointerData Current_last_tid = {{0, 0}, 0};
259 setLastTid(const ItemPointer tid)
261 Current_last_tid = *tid;
265 * Handle CTIDs of views.
266 * CTID should be defined in the view and it must
267 * correspond to the CTID of a base relation.
270 currtid_for_view(Relation viewrel, ItemPointer tid)
272 TupleDesc att = RelationGetDescr(viewrel);
274 RewriteRule *rewrite;
279 for (i = 0; i < natts; i++)
281 if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
283 if (att->attrs[i]->atttypid != TIDOID)
284 elog(ERROR, "ctid isn't of type TID");
290 elog(ERROR, "currtid cannot handle views with no CTID");
291 rulelock = viewrel->rd_rules;
293 elog(ERROR, "the view has no rules");
294 for (i = 0; i < rulelock->numLocks; i++)
296 rewrite = rulelock->rules[i];
297 if (rewrite->event == CMD_SELECT)
302 if (list_length(rewrite->actions) != 1)
303 elog(ERROR, "only one select rule is allowed in views");
304 query = (Query *) linitial(rewrite->actions);
305 tle = get_tle_by_resno(query->targetList, tididx + 1);
306 if (tle && tle->expr && IsA(tle->expr, Var))
308 Var *var = (Var *) tle->expr;
311 if (!IS_SPECIAL_VARNO(var->varno) &&
312 var->varattno == SelfItemPointerAttributeNumber)
314 rte = rt_fetch(var->varno, query->rtable);
317 heap_close(viewrel, AccessShareLock);
318 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
325 elog(ERROR, "currtid cannot handle this view");
330 currtid_byreloid(PG_FUNCTION_ARGS)
332 Oid reloid = PG_GETARG_OID(0);
333 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
339 result = (ItemPointer) palloc(sizeof(ItemPointerData));
342 *result = Current_last_tid;
343 PG_RETURN_ITEMPOINTER(result);
346 rel = heap_open(reloid, AccessShareLock);
348 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
350 if (aclresult != ACLCHECK_OK)
351 aclcheck_error(aclresult, ACL_KIND_CLASS,
352 RelationGetRelationName(rel));
354 if (rel->rd_rel->relkind == RELKIND_VIEW)
355 return currtid_for_view(rel, tid);
357 ItemPointerCopy(tid, result);
359 snapshot = RegisterSnapshot(GetLatestSnapshot());
360 heap_get_latest_tid(rel, snapshot, result);
361 UnregisterSnapshot(snapshot);
363 heap_close(rel, AccessShareLock);
365 PG_RETURN_ITEMPOINTER(result);
369 currtid_byrelname(PG_FUNCTION_ARGS)
371 text *relname = PG_GETARG_TEXT_P(0);
372 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
379 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
380 rel = heap_openrv(relrv, AccessShareLock);
382 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
384 if (aclresult != ACLCHECK_OK)
385 aclcheck_error(aclresult, ACL_KIND_CLASS,
386 RelationGetRelationName(rel));
388 if (rel->rd_rel->relkind == RELKIND_VIEW)
389 return currtid_for_view(rel, tid);
391 result = (ItemPointer) palloc(sizeof(ItemPointerData));
392 ItemPointerCopy(tid, result);
394 snapshot = RegisterSnapshot(GetLatestSnapshot());
395 heap_get_latest_tid(rel, snapshot, result);
396 UnregisterSnapshot(snapshot);
398 heap_close(rel, AccessShareLock);
400 PG_RETURN_ITEMPOINTER(result);