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-2019, 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 "libpq/pqformat.h"
29 #include "miscadmin.h"
30 #include "parser/parsetree.h"
31 #include "utils/acl.h"
32 #include "utils/builtins.h"
33 #include "utils/hashutils.h"
34 #include "utils/rel.h"
35 #include "utils/snapmgr.h"
36 #include "utils/varlena.h"
37 
38 
39 #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
40 #define ItemPointerGetDatum(X) PointerGetDatum(X)
41 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
42 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
43 
44 #define LDELIM '('
45 #define RDELIM ')'
46 #define DELIM ','
47 #define NTIDARGS 2
48 
49 /* ----------------------------------------------------------------
50  * tidin
51  * ----------------------------------------------------------------
52  */
53 Datum
55 {
56  char *str = PG_GETARG_CSTRING(0);
57  char *p,
58  *coord[NTIDARGS];
59  int i;
60  ItemPointer result;
61  BlockNumber blockNumber;
62  OffsetNumber offsetNumber;
63  char *badp;
64  int hold_offset;
65 
66  for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
67  if (*p == DELIM || (*p == LDELIM && !i))
68  coord[i++] = p + 1;
69 
70  if (i < NTIDARGS)
71  ereport(ERROR,
72  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
73  errmsg("invalid input syntax for type %s: \"%s\"",
74  "tid", str)));
75 
76  errno = 0;
77  blockNumber = strtoul(coord[0], &badp, 10);
78  if (errno || *badp != DELIM)
79  ereport(ERROR,
80  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
81  errmsg("invalid input syntax for type %s: \"%s\"",
82  "tid", str)));
83 
84  hold_offset = strtol(coord[1], &badp, 10);
85  if (errno || *badp != RDELIM ||
86  hold_offset > USHRT_MAX || hold_offset < 0)
87  ereport(ERROR,
88  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
89  errmsg("invalid input syntax for type %s: \"%s\"",
90  "tid", str)));
91 
92  offsetNumber = hold_offset;
93 
94  result = (ItemPointer) palloc(sizeof(ItemPointerData));
95 
96  ItemPointerSet(result, blockNumber, offsetNumber);
97 
98  PG_RETURN_ITEMPOINTER(result);
99 }
100 
101 /* ----------------------------------------------------------------
102  * tidout
103  * ----------------------------------------------------------------
104  */
105 Datum
107 {
108  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
109  BlockNumber blockNumber;
110  OffsetNumber offsetNumber;
111  char buf[32];
112 
113  blockNumber = ItemPointerGetBlockNumberNoCheck(itemPtr);
114  offsetNumber = ItemPointerGetOffsetNumberNoCheck(itemPtr);
115 
116  /* Perhaps someday we should output this as a record. */
117  snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
118 
120 }
121 
122 /*
123  * tidrecv - converts external binary format to tid
124  */
125 Datum
127 {
129  ItemPointer result;
130  BlockNumber blockNumber;
131  OffsetNumber offsetNumber;
132 
133  blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
134  offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
135 
136  result = (ItemPointer) palloc(sizeof(ItemPointerData));
137 
138  ItemPointerSet(result, blockNumber, offsetNumber);
139 
140  PG_RETURN_ITEMPOINTER(result);
141 }
142 
143 /*
144  * tidsend - converts tid to binary format
145  */
146 Datum
148 {
149  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
151 
152  pq_begintypsend(&buf);
156 }
157 
158 /*****************************************************************************
159  * PUBLIC ROUTINES *
160  *****************************************************************************/
161 
162 Datum
164 {
167 
168  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
169 }
170 
171 Datum
173 {
176 
177  PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
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_INT32(ItemPointerCompare(arg1, arg2));
223 }
224 
225 Datum
227 {
230 
231  PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
232 }
233 
234 Datum
236 {
239 
240  PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
241 }
242 
243 Datum
245 {
247 
248  /*
249  * While you'll probably have a lot of trouble with a compiler that
250  * insists on appending pad space to struct ItemPointerData, we can at
251  * least make this code work, by not using sizeof(ItemPointerData).
252  * Instead rely on knowing the sizes of the component fields.
253  */
254  return hash_any((unsigned char *) key,
255  sizeof(BlockIdData) + sizeof(OffsetNumber));
256 }
257 
258 Datum
260 {
262  uint64 seed = PG_GETARG_INT64(1);
263 
264  /* As above */
265  return hash_any_extended((unsigned char *) key,
266  sizeof(BlockIdData) + sizeof(OffsetNumber),
267  seed);
268 }
269 
270 
271 /*
272  * Functions to get latest tid of a specified tuple.
273  *
274  * Maybe these implementations should be moved to another place
275  */
276 
277 static ItemPointerData Current_last_tid = {{0, 0}, 0};
278 
279 void
281 {
282  Current_last_tid = *tid;
283 }
284 
285 /*
286  * Handle CTIDs of views.
287  * CTID should be defined in the view and it must
288  * correspond to the CTID of a base relation.
289  */
290 static Datum
292 {
293  TupleDesc att = RelationGetDescr(viewrel);
294  RuleLock *rulelock;
295  RewriteRule *rewrite;
296  int i,
297  natts = att->natts,
298  tididx = -1;
299 
300  for (i = 0; i < natts; i++)
301  {
302  Form_pg_attribute attr = TupleDescAttr(att, i);
303 
304  if (strcmp(NameStr(attr->attname), "ctid") == 0)
305  {
306  if (attr->atttypid != TIDOID)
307  elog(ERROR, "ctid isn't of type TID");
308  tididx = i;
309  break;
310  }
311  }
312  if (tididx < 0)
313  elog(ERROR, "currtid cannot handle views with no CTID");
314  rulelock = viewrel->rd_rules;
315  if (!rulelock)
316  elog(ERROR, "the view has no rules");
317  for (i = 0; i < rulelock->numLocks; i++)
318  {
319  rewrite = rulelock->rules[i];
320  if (rewrite->event == CMD_SELECT)
321  {
322  Query *query;
323  TargetEntry *tle;
324 
325  if (list_length(rewrite->actions) != 1)
326  elog(ERROR, "only one select rule is allowed in views");
327  query = (Query *) linitial(rewrite->actions);
328  tle = get_tle_by_resno(query->targetList, tididx + 1);
329  if (tle && tle->expr && IsA(tle->expr, Var))
330  {
331  Var *var = (Var *) tle->expr;
332  RangeTblEntry *rte;
333 
334  if (!IS_SPECIAL_VARNO(var->varno) &&
336  {
337  rte = rt_fetch(var->varno, query->rtable);
338  if (rte)
339  {
340  table_close(viewrel, AccessShareLock);
342  }
343  }
344  }
345  break;
346  }
347  }
348  elog(ERROR, "currtid cannot handle this view");
349  return (Datum) 0;
350 }
351 
352 Datum
354 {
355  Oid reloid = PG_GETARG_OID(0);
357  ItemPointer result;
358  Relation rel;
359  AclResult aclresult;
360  Snapshot snapshot;
361  TableScanDesc scan;
362 
363  result = (ItemPointer) palloc(sizeof(ItemPointerData));
364  if (!reloid)
365  {
366  *result = Current_last_tid;
367  PG_RETURN_ITEMPOINTER(result);
368  }
369 
370  rel = table_open(reloid, AccessShareLock);
371 
372  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
373  ACL_SELECT);
374  if (aclresult != ACLCHECK_OK)
375  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
377 
378  if (rel->rd_rel->relkind == RELKIND_VIEW)
379  return currtid_for_view(rel, tid);
380 
381  ItemPointerCopy(tid, result);
382 
383  snapshot = RegisterSnapshot(GetLatestSnapshot());
384  scan = table_beginscan(rel, snapshot, 0, NULL);
385  table_tuple_get_latest_tid(scan, result);
386  table_endscan(scan);
387  UnregisterSnapshot(snapshot);
388 
390 
391  PG_RETURN_ITEMPOINTER(result);
392 }
393 
394 Datum
396 {
399  ItemPointer result;
400  RangeVar *relrv;
401  Relation rel;
402  AclResult aclresult;
403  Snapshot snapshot;
404  TableScanDesc scan;
405 
407  rel = table_openrv(relrv, AccessShareLock);
408 
409  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
410  ACL_SELECT);
411  if (aclresult != ACLCHECK_OK)
412  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
414 
415  if (rel->rd_rel->relkind == RELKIND_VIEW)
416  return currtid_for_view(rel, tid);
417 
418  result = (ItemPointer) palloc(sizeof(ItemPointerData));
419  ItemPointerCopy(tid, result);
420 
421  snapshot = RegisterSnapshot(GetLatestSnapshot());
422  scan = table_beginscan(rel, snapshot, 0, NULL);
423  table_tuple_get_latest_tid(scan, result);
424  table_endscan(scan);
425  UnregisterSnapshot(snapshot);
426 
428 
429  PG_RETURN_ITEMPOINTER(result);
430 }
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
Datum tidlt(PG_FUNCTION_ARGS)
Definition: tid.c:181
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:217
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int numLocks
Definition: prs2lock.h:42
Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.c:148
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
#define RelationGetDescr(relation)
Definition: rel.h:445
#define PG_GETARG_ITEMPOINTER(n)
Definition: tid.c:41
Oid GetUserId(void)
Definition: miscinit.c:380
#define LDELIM
Definition: tid.c:44
Datum tidsmaller(PG_FUNCTION_ARGS)
Definition: tid.c:235
#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:259
StringInfoData * StringInfo
Definition: stringinfo.h:43
#define RDELIM
Definition: tid.c:45
#define PG_RETURN_INT32(x)
Definition: fmgr.h:344
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:570
#define NTIDARGS
Definition: tid.c:47
AttrNumber varattno
Definition: primnodes.h:172
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
uint32 BlockNumber
Definition: block.h:31
Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.c:374
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3054
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:360
Form_pg_class rd_rel
Definition: rel.h:83
NameData relname
Definition: pg_class.h:35
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:167
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
List * targetList
Definition: parsenodes.h:140
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:49
static Datum currtid_for_view(Relation viewrel, ItemPointer tid)
Definition: tid.c:291
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:145
Datum tidsend(PG_FUNCTION_ARGS)
Definition: tid.c:147
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:161
#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:353
static ItemPointerData Current_last_tid
Definition: tid.c:277
#define PG_RETURN_ITEMPOINTER(x)
Definition: tid.c:42
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:736
static char * buf
Definition: pg_test_fsync.c:68
Datum tidrecv(PG_FUNCTION_ARGS)
Definition: tid.c:126
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
CmdType event
Definition: prs2lock.h:27
void table_tuple_get_latest_tid(TableScanDesc scan, ItemPointer tid)
Definition: tableam.c:228
#define RelationGetRelationName(relation)
Definition: rel.h:453
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
void setLastTid(const ItemPointer tid)
Definition: tid.c:280
#define ereport(elevel, rest)
Definition: elog.h:141
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3586
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
Datum tidge(PG_FUNCTION_ARGS)
Definition: tid.c:208
Index varno
Definition: primnodes.h:170
Datum tidle(PG_FUNCTION_ARGS)
Definition: tid.c:190
Datum tidlarger(PG_FUNCTION_ARGS)
Definition: tid.c:226
AclResult
Definition: acl.h:177
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
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:46
Datum tidin(PG_FUNCTION_ARGS)
Definition: tid.c:54
Expr * expr
Definition: primnodes.h:1393
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:352
RuleLock * rd_rules
Definition: rel.h:87
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:4631
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:831
Datum currtid_byrelname(PG_FUNCTION_ARGS)
Definition: tid.c:395
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define ItemPointerGetBlockNumberNoCheck(pointer)
Definition: itemptr.h:89
Datum hashtid(PG_FUNCTION_ARGS)
Definition: tid.c:244
#define elog(elevel,...)
Definition: elog.h:226
int i
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:609
Datum tidgt(PG_FUNCTION_ARGS)
Definition: tid.c:199
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:272
Datum tidne(PG_FUNCTION_ARGS)
Definition: tid.c:172
Definition: c.h:549
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
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:277
#define snprintf
Definition: port.h:192
Datum tidout(PG_FUNCTION_ARGS)
Definition: tid.c:106
#define RelationGetRelid(relation)
Definition: rel.h:419
Datum tideq(PG_FUNCTION_ARGS)
Definition: tid.c:163
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:619
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:161