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