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-2022, 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 
51 
52 /* ----------------------------------------------------------------
53  * tidin
54  * ----------------------------------------------------------------
55  */
56 Datum
58 {
59  char *str = PG_GETARG_CSTRING(0);
60  char *p,
61  *coord[NTIDARGS];
62  int i;
63  ItemPointer result;
64  BlockNumber blockNumber;
65  OffsetNumber offsetNumber;
66  char *badp;
67  unsigned long cvt;
68 
69  for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
70  if (*p == DELIM || (*p == LDELIM && i == 0))
71  coord[i++] = p + 1;
72 
73  if (i < NTIDARGS)
74  ereport(ERROR,
75  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
76  errmsg("invalid input syntax for type %s: \"%s\"",
77  "tid", str)));
78 
79  errno = 0;
80  cvt = strtoul(coord[0], &badp, 10);
81  if (errno || *badp != DELIM)
82  ereport(ERROR,
83  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
84  errmsg("invalid input syntax for type %s: \"%s\"",
85  "tid", str)));
86  blockNumber = (BlockNumber) cvt;
87 
88  /*
89  * Cope with possibility that unsigned long is wider than BlockNumber, in
90  * which case strtoul will not raise an error for some values that are out
91  * of the range of BlockNumber. (See similar code in oidin().)
92  */
93 #if SIZEOF_LONG > 4
94  if (cvt != (unsigned long) blockNumber &&
95  cvt != (unsigned long) ((int32) blockNumber))
96  ereport(ERROR,
97  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
98  errmsg("invalid input syntax for type %s: \"%s\"",
99  "tid", str)));
100 #endif
101 
102  cvt = strtoul(coord[1], &badp, 10);
103  if (errno || *badp != RDELIM ||
104  cvt > USHRT_MAX)
105  ereport(ERROR,
106  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
107  errmsg("invalid input syntax for type %s: \"%s\"",
108  "tid", str)));
109  offsetNumber = (OffsetNumber) cvt;
110 
111  result = (ItemPointer) palloc(sizeof(ItemPointerData));
112 
113  ItemPointerSet(result, blockNumber, offsetNumber);
114 
115  PG_RETURN_ITEMPOINTER(result);
116 }
117 
118 /* ----------------------------------------------------------------
119  * tidout
120  * ----------------------------------------------------------------
121  */
122 Datum
124 {
125  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
126  BlockNumber blockNumber;
127  OffsetNumber offsetNumber;
128  char buf[32];
129 
130  blockNumber = ItemPointerGetBlockNumberNoCheck(itemPtr);
131  offsetNumber = ItemPointerGetOffsetNumberNoCheck(itemPtr);
132 
133  /* Perhaps someday we should output this as a record. */
134  snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
135 
137 }
138 
139 /*
140  * tidrecv - converts external binary format to tid
141  */
142 Datum
144 {
146  ItemPointer result;
147  BlockNumber blockNumber;
148  OffsetNumber offsetNumber;
149 
150  blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
151  offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
152 
153  result = (ItemPointer) palloc(sizeof(ItemPointerData));
154 
155  ItemPointerSet(result, blockNumber, offsetNumber);
156 
157  PG_RETURN_ITEMPOINTER(result);
158 }
159 
160 /*
161  * tidsend - converts tid to binary format
162  */
163 Datum
165 {
166  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
168 
173 }
174 
175 /*****************************************************************************
176  * PUBLIC ROUTINES *
177  *****************************************************************************/
178 
179 Datum
181 {
184 
185  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
186 }
187 
188 Datum
190 {
193 
194  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
195 }
196 
197 Datum
199 {
202 
203  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
204 }
205 
206 Datum
208 {
211 
212  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
213 }
214 
215 Datum
217 {
220 
221  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
222 }
223 
224 Datum
226 {
229 
230  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
231 }
232 
233 Datum
235 {
238 
239  PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
240 }
241 
242 Datum
244 {
247 
248  PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
249 }
250 
251 Datum
253 {
256 
257  PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
258 }
259 
260 Datum
262 {
264 
265  /*
266  * While you'll probably have a lot of trouble with a compiler that
267  * insists on appending pad space to struct ItemPointerData, we can at
268  * least make this code work, by not using sizeof(ItemPointerData).
269  * Instead rely on knowing the sizes of the component fields.
270  */
271  return hash_any((unsigned char *) key,
272  sizeof(BlockIdData) + sizeof(OffsetNumber));
273 }
274 
275 Datum
277 {
279  uint64 seed = PG_GETARG_INT64(1);
280 
281  /* As above */
282  return hash_any_extended((unsigned char *) key,
283  sizeof(BlockIdData) + sizeof(OffsetNumber),
284  seed);
285 }
286 
287 
288 /*
289  * Functions to get latest tid of a specified tuple.
290  *
291  * Maybe these implementations should be moved to another place
292  */
293 
294 /*
295  * Utility wrapper for current CTID functions.
296  * Returns the latest version of a tuple pointing at "tid" for
297  * relation "rel".
298  */
299 static ItemPointer
301 {
302  ItemPointer result;
303  AclResult aclresult;
304  Snapshot snapshot;
305  TableScanDesc scan;
306 
307  result = (ItemPointer) palloc(sizeof(ItemPointerData));
308 
309  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
310  ACL_SELECT);
311  if (aclresult != ACLCHECK_OK)
312  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
314 
315  if (rel->rd_rel->relkind == RELKIND_VIEW)
316  return currtid_for_view(rel, tid);
317 
318  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
319  elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
322 
323  ItemPointerCopy(tid, result);
324 
325  snapshot = RegisterSnapshot(GetLatestSnapshot());
326  scan = table_beginscan_tid(rel, snapshot);
327  table_tuple_get_latest_tid(scan, result);
328  table_endscan(scan);
329  UnregisterSnapshot(snapshot);
330 
331  return result;
332 }
333 
334 /*
335  * Handle CTIDs of views.
336  * CTID should be defined in the view and it must
337  * correspond to the CTID of a base relation.
338  */
339 static ItemPointer
341 {
342  TupleDesc att = RelationGetDescr(viewrel);
343  RuleLock *rulelock;
344  RewriteRule *rewrite;
345  int i,
346  natts = att->natts,
347  tididx = -1;
348 
349  for (i = 0; i < natts; i++)
350  {
351  Form_pg_attribute attr = TupleDescAttr(att, i);
352 
353  if (strcmp(NameStr(attr->attname), "ctid") == 0)
354  {
355  if (attr->atttypid != TIDOID)
356  elog(ERROR, "ctid isn't of type TID");
357  tididx = i;
358  break;
359  }
360  }
361  if (tididx < 0)
362  elog(ERROR, "currtid cannot handle views with no CTID");
363  rulelock = viewrel->rd_rules;
364  if (!rulelock)
365  elog(ERROR, "the view has no rules");
366  for (i = 0; i < rulelock->numLocks; i++)
367  {
368  rewrite = rulelock->rules[i];
369  if (rewrite->event == CMD_SELECT)
370  {
371  Query *query;
372  TargetEntry *tle;
373 
374  if (list_length(rewrite->actions) != 1)
375  elog(ERROR, "only one select rule is allowed in views");
376  query = (Query *) linitial(rewrite->actions);
377  tle = get_tle_by_resno(query->targetList, tididx + 1);
378  if (tle && tle->expr && IsA(tle->expr, Var))
379  {
380  Var *var = (Var *) tle->expr;
381  RangeTblEntry *rte;
382 
383  if (!IS_SPECIAL_VARNO(var->varno) &&
385  {
386  rte = rt_fetch(var->varno, query->rtable);
387  if (rte)
388  {
389  ItemPointer result;
390  Relation rel;
391 
392  rel = table_open(rte->relid, AccessShareLock);
393  result = currtid_internal(rel, tid);
395  return result;
396  }
397  }
398  }
399  break;
400  }
401  }
402  elog(ERROR, "currtid cannot handle this view");
403  return NULL;
404 }
405 
406 /*
407  * currtid_byrelname
408  * Get the latest tuple version of the tuple pointing at a CTID, for a
409  * given relation name.
410  */
411 Datum
413 {
416  ItemPointer result;
417  RangeVar *relrv;
418  Relation rel;
419 
421  rel = table_openrv(relrv, AccessShareLock);
422 
423  /* grab the latest tuple version associated to this CTID */
424  result = currtid_internal(rel, tid);
425 
427 
428  PG_RETURN_ITEMPOINTER(result);
429 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5007
uint32 BlockNumber
Definition: block.h:31
#define NameStr(name)
Definition: c.h:681
signed int int32
Definition: c.h:429
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define ereport(elevel,...)
Definition: elog.h:143
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
int i
Definition: isn.c:73
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
#define ItemPointerGetBlockNumberNoCheck(pointer)
Definition: itemptr.h:89
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:161
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127
ItemPointerData * ItemPointer
Definition: itemptr.h:49
#define ItemPointerGetOffsetNumberNoCheck(pointer)
Definition: itemptr.h:108
#define AccessShareLock
Definition: lockdefs.h:36
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
char * pstrdup(const char *in)
Definition: mcxt.c:1305
void * palloc(Size size)
Definition: mcxt.c:1068
Oid GetUserId(void)
Definition: miscinit.c:492
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3108
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
@ CMD_SELECT
Definition: nodes.h:721
ObjectType get_relkind_objtype(char relkind)
uint16 OffsetNumber
Definition: off.h:24
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define ACL_SELECT
Definition: parsenodes.h:83
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
NameData relname
Definition: pg_class.h:38
static int list_length(const List *l)
Definition: pg_list.h:149
#define linitial(l)
Definition: pg_list.h:174
static char * buf
Definition: pg_test_fsync.c:67
#define snprintf
Definition: port.h:225
uintptr_t Datum
Definition: postgres.h:411
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:145
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:137
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:189
#define RelationGetRelid(relation)
Definition: rel.h:489
#define RelationGetDescr(relation)
Definition: rel.h:515
#define RelationGetRelationName(relation)
Definition: rel.h:523
#define RelationGetNamespace(relation)
Definition: rel.h:530
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:325
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:869
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:827
StringInfoData * StringInfo
Definition: stringinfo.h:44
List * rtable
Definition: parsenodes.h:148
List * targetList
Definition: parsenodes.h:155
RuleLock * rd_rules
Definition: rel.h:113
Form_pg_class rd_rel
Definition: rel.h:109
CmdType event
Definition: prs2lock.h:27
List * actions
Definition: prs2lock.h:29
RewriteRule ** rules
Definition: prs2lock.h:43
int numLocks
Definition: prs2lock.h:42
Expr * expr
Definition: primnodes.h:1716
Definition: primnodes.h:196
AttrNumber varattno
Definition: primnodes.h:200
int varno
Definition: primnodes.h:198
Definition: c.h:622
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:102
void table_tuple_get_latest_tid(TableScanDesc scan, ItemPointer tid)
Definition: tableam.c:246
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:993
static TableScanDesc table_beginscan_tid(Relation rel, Snapshot snapshot)
Definition: tableam.h:969
Datum tidge(PG_FUNCTION_ARGS)
Definition: tid.c:225
#define DELIM
Definition: tid.c:47
Datum bttidcmp(PG_FUNCTION_ARGS)
Definition: tid.c:234
Datum currtid_byrelname(PG_FUNCTION_ARGS)
Definition: tid.c:412
static ItemPointer currtid_internal(Relation rel, ItemPointer tid)
Definition: tid.c:300
Datum hashtid(PG_FUNCTION_ARGS)
Definition: tid.c:261
Datum tidlarger(PG_FUNCTION_ARGS)
Definition: tid.c:243
#define PG_RETURN_ITEMPOINTER(x)
Definition: tid.c:43
#define NTIDARGS
Definition: tid.c:48
Datum hashtidextended(PG_FUNCTION_ARGS)
Definition: tid.c:276
Datum tideq(PG_FUNCTION_ARGS)
Definition: tid.c:180
Datum tidgt(PG_FUNCTION_ARGS)
Definition: tid.c:216
Datum tidin(PG_FUNCTION_ARGS)
Definition: tid.c:57
Datum tidle(PG_FUNCTION_ARGS)
Definition: tid.c:207
#define RDELIM
Definition: tid.c:46
#define PG_GETARG_ITEMPOINTER(n)
Definition: tid.c:42
Datum tidsmaller(PG_FUNCTION_ARGS)
Definition: tid.c:252
Datum tidne(PG_FUNCTION_ARGS)
Definition: tid.c:189
static ItemPointer currtid_for_view(Relation viewrel, ItemPointer tid)
Definition: tid.c:340
Datum tidrecv(PG_FUNCTION_ARGS)
Definition: tid.c:143
Datum tidout(PG_FUNCTION_ARGS)
Definition: tid.c:123
Datum tidsend(PG_FUNCTION_ARGS)
Definition: tid.c:164
Datum tidlt(PG_FUNCTION_ARGS)
Definition: tid.c:198
#define LDELIM
Definition: tid.c:45
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3657