PostgreSQL Source Code  git master
tid.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * tid.c
4  * Functions for the built-in type tuple id
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/adt/tid.c
12  *
13  * NOTES
14  * input routine largely stolen from boxin().
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19 
20 #include <math.h>
21 #include <limits.h>
22 
23 #include "access/heapam.h"
24 #include "access/sysattr.h"
25 #include "access/tableam.h"
26 #include "catalog/namespace.h"
27 #include "catalog/pg_type.h"
28 #include "common/hashfn.h"
29 #include "libpq/pqformat.h"
30 #include "miscadmin.h"
31 #include "parser/parsetree.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35 #include "utils/rel.h"
36 #include "utils/snapmgr.h"
37 #include "utils/varlena.h"
38 
39 
40 #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
41 #define ItemPointerGetDatum(X) PointerGetDatum(X)
42 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
43 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
44 
45 #define LDELIM '('
46 #define RDELIM ')'
47 #define DELIM ','
48 #define NTIDARGS 2
49 
50 /* ----------------------------------------------------------------
51  * tidin
52  * ----------------------------------------------------------------
53  */
54 Datum
56 {
57  char *str = PG_GETARG_CSTRING(0);
58  char *p,
59  *coord[NTIDARGS];
60  int i;
61  ItemPointer result;
62  BlockNumber blockNumber;
63  OffsetNumber offsetNumber;
64  char *badp;
65  int hold_offset;
66 
67  for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
68  if (*p == DELIM || (*p == LDELIM && !i))
69  coord[i++] = p + 1;
70 
71  if (i < NTIDARGS)
72  ereport(ERROR,
73  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
74  errmsg("invalid input syntax for type %s: \"%s\"",
75  "tid", str)));
76 
77  errno = 0;
78  blockNumber = strtoul(coord[0], &badp, 10);
79  if (errno || *badp != DELIM)
80  ereport(ERROR,
81  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
82  errmsg("invalid input syntax for type %s: \"%s\"",
83  "tid", str)));
84 
85  hold_offset = strtol(coord[1], &badp, 10);
86  if (errno || *badp != RDELIM ||
87  hold_offset > USHRT_MAX || hold_offset < 0)
88  ereport(ERROR,
89  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
90  errmsg("invalid input syntax for type %s: \"%s\"",
91  "tid", str)));
92 
93  offsetNumber = hold_offset;
94 
95  result = (ItemPointer) palloc(sizeof(ItemPointerData));
96 
97  ItemPointerSet(result, blockNumber, offsetNumber);
98 
99  PG_RETURN_ITEMPOINTER(result);
100 }
101 
102 /* ----------------------------------------------------------------
103  * tidout
104  * ----------------------------------------------------------------
105  */
106 Datum
108 {
109  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
110  BlockNumber blockNumber;
111  OffsetNumber offsetNumber;
112  char buf[32];
113 
114  blockNumber = ItemPointerGetBlockNumberNoCheck(itemPtr);
115  offsetNumber = ItemPointerGetOffsetNumberNoCheck(itemPtr);
116 
117  /* Perhaps someday we should output this as a record. */
118  snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
119 
121 }
122 
123 /*
124  * tidrecv - converts external binary format to tid
125  */
126 Datum
128 {
130  ItemPointer result;
131  BlockNumber blockNumber;
132  OffsetNumber offsetNumber;
133 
134  blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
135  offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
136 
137  result = (ItemPointer) palloc(sizeof(ItemPointerData));
138 
139  ItemPointerSet(result, blockNumber, offsetNumber);
140 
141  PG_RETURN_ITEMPOINTER(result);
142 }
143 
144 /*
145  * tidsend - converts tid to binary format
146  */
147 Datum
149 {
150  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
152 
153  pq_begintypsend(&buf);
157 }
158 
159 /*****************************************************************************
160  * PUBLIC ROUTINES *
161  *****************************************************************************/
162 
163 Datum
165 {
168 
169  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
170 }
171 
172 Datum
174 {
177 
178  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
179 }
180 
181 Datum
183 {
186 
187  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
188 }
189 
190 Datum
192 {
195 
196  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
197 }
198 
199 Datum
201 {
204 
205  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
206 }
207 
208 Datum
210 {
213 
214  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
215 }
216 
217 Datum
219 {
222 
223  PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
224 }
225 
226 Datum
228 {
231 
232  PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
233 }
234 
235 Datum
237 {
240 
241  PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
242 }
243 
244 Datum
246 {
248 
249  /*
250  * While you'll probably have a lot of trouble with a compiler that
251  * insists on appending pad space to struct ItemPointerData, we can at
252  * least make this code work, by not using sizeof(ItemPointerData).
253  * Instead rely on knowing the sizes of the component fields.
254  */
255  return hash_any((unsigned char *) key,
256  sizeof(BlockIdData) + sizeof(OffsetNumber));
257 }
258 
259 Datum
261 {
263  uint64 seed = PG_GETARG_INT64(1);
264 
265  /* As above */
266  return hash_any_extended((unsigned char *) key,
267  sizeof(BlockIdData) + sizeof(OffsetNumber),
268  seed);
269 }
270 
271 
272 /*
273  * Functions to get latest tid of a specified tuple.
274  *
275  * Maybe these implementations should be moved to another place
276  */
277 
278 static ItemPointerData Current_last_tid = {{0, 0}, 0};
279 
280 void
282 {
283  Current_last_tid = *tid;
284 }
285 
286 /*
287  * Handle CTIDs of views.
288  * CTID should be defined in the view and it must
289  * correspond to the CTID of a base relation.
290  */
291 static Datum
293 {
294  TupleDesc att = RelationGetDescr(viewrel);
295  RuleLock *rulelock;
296  RewriteRule *rewrite;
297  int i,
298  natts = att->natts,
299  tididx = -1;
300 
301  for (i = 0; i < natts; i++)
302  {
303  Form_pg_attribute attr = TupleDescAttr(att, i);
304 
305  if (strcmp(NameStr(attr->attname), "ctid") == 0)
306  {
307  if (attr->atttypid != TIDOID)
308  elog(ERROR, "ctid isn't of type TID");
309  tididx = i;
310  break;
311  }
312  }
313  if (tididx < 0)
314  elog(ERROR, "currtid cannot handle views with no CTID");
315  rulelock = viewrel->rd_rules;
316  if (!rulelock)
317  elog(ERROR, "the view has no rules");
318  for (i = 0; i < rulelock->numLocks; i++)
319  {
320  rewrite = rulelock->rules[i];
321  if (rewrite->event == CMD_SELECT)
322  {
323  Query *query;
324  TargetEntry *tle;
325 
326  if (list_length(rewrite->actions) != 1)
327  elog(ERROR, "only one select rule is allowed in views");
328  query = (Query *) linitial(rewrite->actions);
329  tle = get_tle_by_resno(query->targetList, tididx + 1);
330  if (tle && tle->expr && IsA(tle->expr, Var))
331  {
332  Var *var = (Var *) tle->expr;
333  RangeTblEntry *rte;
334 
335  if (!IS_SPECIAL_VARNO(var->varno) &&
337  {
338  rte = rt_fetch(var->varno, query->rtable);
339  if (rte)
340  {
341  Datum result;
342 
344  ObjectIdGetDatum(rte->relid),
345  PointerGetDatum(tid));
346  table_close(viewrel, AccessShareLock);
347  return result;
348  }
349  }
350  }
351  break;
352  }
353  }
354  elog(ERROR, "currtid cannot handle this view");
355  return (Datum) 0;
356 }
357 
358 Datum
360 {
361  Oid reloid = PG_GETARG_OID(0);
363  ItemPointer result;
364  Relation rel;
365  AclResult aclresult;
366  Snapshot snapshot;
367  TableScanDesc scan;
368 
369  result = (ItemPointer) palloc(sizeof(ItemPointerData));
370  if (!reloid)
371  {
372  *result = Current_last_tid;
373  PG_RETURN_ITEMPOINTER(result);
374  }
375 
376  rel = table_open(reloid, AccessShareLock);
377 
378  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
379  ACL_SELECT);
380  if (aclresult != ACLCHECK_OK)
381  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
383 
384  if (rel->rd_rel->relkind == RELKIND_VIEW)
385  return currtid_for_view(rel, tid);
386 
387  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
388  elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
391 
392  ItemPointerCopy(tid, result);
393 
394  snapshot = RegisterSnapshot(GetLatestSnapshot());
395  scan = table_beginscan_tid(rel, snapshot);
396  table_tuple_get_latest_tid(scan, result);
397  table_endscan(scan);
398  UnregisterSnapshot(snapshot);
399 
401 
402  PG_RETURN_ITEMPOINTER(result);
403 }
404 
405 Datum
407 {
410  ItemPointer result;
411  RangeVar *relrv;
412  Relation rel;
413  AclResult aclresult;
414  Snapshot snapshot;
415  TableScanDesc scan;
416 
418  rel = table_openrv(relrv, AccessShareLock);
419 
420  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
421  ACL_SELECT);
422  if (aclresult != ACLCHECK_OK)
423  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
425 
426  if (rel->rd_rel->relkind == RELKIND_VIEW)
427  return currtid_for_view(rel, tid);
428 
429  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
430  elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
433 
434  result = (ItemPointer) palloc(sizeof(ItemPointerData));
435  ItemPointerCopy(tid, result);
436 
437  snapshot = RegisterSnapshot(GetLatestSnapshot());
438  scan = table_beginscan_tid(rel, snapshot);
439  table_tuple_get_latest_tid(scan, result);
440  table_endscan(scan);
441  UnregisterSnapshot(snapshot);
442 
444 
445  PG_RETURN_ITEMPOINTER(result);
446 }
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
Datum tidlt(PG_FUNCTION_ARGS)
Definition: tid.c:182
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:137
#define ItemPointerGetOffsetNumberNoCheck(pointer)
Definition: itemptr.h:108
Datum bttidcmp(PG_FUNCTION_ARGS)
Definition: tid.c:218
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int numLocks
Definition: prs2lock.h:42
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
#define RelationGetDescr(relation)
Definition: rel.h:482
#define PG_GETARG_ITEMPOINTER(n)
Definition: tid.c:42
Oid GetUserId(void)
Definition: miscinit.c:450
#define LDELIM
Definition: tid.c:45
Datum tidsmaller(PG_FUNCTION_ARGS)
Definition: tid.c:236
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
char * pstrdup(const char *in)
Definition: mcxt.c:1186
Datum hashtidextended(PG_FUNCTION_ARGS)
Definition: tid.c:260
StringInfoData * StringInfo
Definition: stringinfo.h:44
#define RDELIM
Definition: tid.c:46
#define PG_RETURN_INT32(x)
Definition: fmgr.h:353
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
#define NTIDARGS
Definition: tid.c:48
AttrNumber varattno
Definition: primnodes.h:186
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
uint32 BlockNumber
Definition: block.h:31
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3062
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:369
Form_pg_class rd_rel
Definition: rel.h:109
NameData relname
Definition: pg_class.h:38
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:181
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
List * targetList
Definition: parsenodes.h:140
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:308
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:49
static Datum currtid_for_view(Relation viewrel, ItemPointer tid)
Definition: tid.c:292
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:145
Datum tidsend(PG_FUNCTION_ARGS)
Definition: tid.c:148
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:175
#define linitial(l)
Definition: pg_list.h:195
List * rtable
Definition: parsenodes.h:137
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Datum currtid_byreloid(PG_FUNCTION_ARGS)
Definition: tid.c:359
static ItemPointerData Current_last_tid
Definition: tid.c:278
#define PG_RETURN_ITEMPOINTER(x)
Definition: tid.c:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
static char * buf
Definition: pg_test_fsync.c:67
Datum tidrecv(PG_FUNCTION_ARGS)
Definition: tid.c:127
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
CmdType event
Definition: prs2lock.h:27
void table_tuple_get_latest_tid(TableScanDesc scan, ItemPointer tid)
Definition: tableam.c:246
#define RelationGetRelationName(relation)
Definition: rel.h:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
void setLastTid(const ItemPointer tid)
Definition: tid.c:281
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3628
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
Datum tidge(PG_FUNCTION_ARGS)
Definition: tid.c:209
Index varno
Definition: primnodes.h:184
Datum tidle(PG_FUNCTION_ARGS)
Definition: tid.c:191
Datum tidlarger(PG_FUNCTION_ARGS)
Definition: tid.c:227
AclResult
Definition: acl.h:177
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:358
uintptr_t Datum
Definition: postgres.h:367
#define ACL_SELECT
Definition: parsenodes.h:75
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:68
#define DELIM
Definition: tid.c:47
#define ereport(elevel,...)
Definition: elog.h:144
Datum tidin(PG_FUNCTION_ARGS)
Definition: tid.c:55
Expr * expr
Definition: primnodes.h:1407
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:361
RuleLock * rd_rules
Definition: rel.h:113
static int list_length(const List *l)
Definition: pg_list.h:169
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4563
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:863
static TableScanDesc table_beginscan_tid(Relation rel, Snapshot snapshot)
Definition: tableam.h:839
Datum currtid_byrelname(PG_FUNCTION_ARGS)
Definition: tid.c:406
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ItemPointerGetBlockNumberNoCheck(pointer)
Definition: itemptr.h:89
Datum hashtid(PG_FUNCTION_ARGS)
Definition: tid.c:245
#define elog(elevel,...)
Definition: elog.h:214
int i
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:622
Datum tidgt(PG_FUNCTION_ARGS)
Definition: tid.c:200
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
Datum tidne(PG_FUNCTION_ARGS)
Definition: tid.c:173
Definition: c.h:562
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define PG_GETARG_INT64(n)
Definition: fmgr.h:282
#define snprintf
Definition: port.h:193
Datum tidout(PG_FUNCTION_ARGS)
Definition: tid.c:107
#define RelationGetRelid(relation)
Definition: rel.h:456
Datum tideq(PG_FUNCTION_ARGS)
Definition: tid.c:164
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:626
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:161
#define RelationGetNamespace(relation)
Definition: rel.h:497