PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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 "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"
36 
37 
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)
42 
43 #define LDELIM '('
44 #define RDELIM ')'
45 #define DELIM ','
46 #define NTIDARGS 2
47 
48 /* ----------------------------------------------------------------
49  * tidin
50  * ----------------------------------------------------------------
51  */
52 Datum
54 {
55  char *str = PG_GETARG_CSTRING(0);
56  char *p,
57  *coord[NTIDARGS];
58  int i;
60  BlockNumber blockNumber;
61  OffsetNumber offsetNumber;
62  char *badp;
63  int hold_offset;
64 
65  for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
66  if (*p == DELIM || (*p == LDELIM && !i))
67  coord[i++] = p + 1;
68 
69  if (i < NTIDARGS)
70  ereport(ERROR,
71  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
72  errmsg("invalid input syntax for type %s: \"%s\"",
73  "tid", str)));
74 
75  errno = 0;
76  blockNumber = strtoul(coord[0], &badp, 10);
77  if (errno || *badp != DELIM)
78  ereport(ERROR,
79  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
80  errmsg("invalid input syntax for type %s: \"%s\"",
81  "tid", str)));
82 
83  hold_offset = strtol(coord[1], &badp, 10);
84  if (errno || *badp != RDELIM ||
85  hold_offset > USHRT_MAX || hold_offset < 0)
86  ereport(ERROR,
87  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
88  errmsg("invalid input syntax for type %s: \"%s\"",
89  "tid", str)));
90 
91  offsetNumber = hold_offset;
92 
93  result = (ItemPointer) palloc(sizeof(ItemPointerData));
94 
95  ItemPointerSet(result, blockNumber, offsetNumber);
96 
97  PG_RETURN_ITEMPOINTER(result);
98 }
99 
100 /* ----------------------------------------------------------------
101  * tidout
102  * ----------------------------------------------------------------
103  */
104 Datum
106 {
107  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
108  BlockNumber blockNumber;
109  OffsetNumber offsetNumber;
110  char buf[32];
111 
112  blockNumber = ItemPointerGetBlockNumberNoCheck(itemPtr);
113  offsetNumber = ItemPointerGetOffsetNumberNoCheck(itemPtr);
114 
115  /* Perhaps someday we should output this as a record. */
116  snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
117 
119 }
120 
121 /*
122  * tidrecv - converts external binary format to tid
123  */
124 Datum
126 {
129  BlockNumber blockNumber;
130  OffsetNumber offsetNumber;
131 
132  blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
133  offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
134 
135  result = (ItemPointer) palloc(sizeof(ItemPointerData));
136 
137  ItemPointerSet(result, blockNumber, offsetNumber);
138 
139  PG_RETURN_ITEMPOINTER(result);
140 }
141 
142 /*
143  * tidsend - converts tid to binary format
144  */
145 Datum
147 {
148  ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
150 
151  pq_begintypsend(&buf);
153  sizeof(BlockNumber));
155  sizeof(OffsetNumber));
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 
245 /*
246  * Functions to get latest tid of a specified tuple.
247  *
248  * Maybe these implementations should be moved to another place
249  */
250 
251 static ItemPointerData Current_last_tid = {{0, 0}, 0};
252 
253 void
255 {
256  Current_last_tid = *tid;
257 }
258 
259 /*
260  * Handle CTIDs of views.
261  * CTID should be defined in the view and it must
262  * correspond to the CTID of a base relation.
263  */
264 static Datum
266 {
267  TupleDesc att = RelationGetDescr(viewrel);
268  RuleLock *rulelock;
269  RewriteRule *rewrite;
270  int i,
271  natts = att->natts,
272  tididx = -1;
273 
274  for (i = 0; i < natts; i++)
275  {
276  Form_pg_attribute attr = TupleDescAttr(att, i);
277 
278  if (strcmp(NameStr(attr->attname), "ctid") == 0)
279  {
280  if (attr->atttypid != TIDOID)
281  elog(ERROR, "ctid isn't of type TID");
282  tididx = i;
283  break;
284  }
285  }
286  if (tididx < 0)
287  elog(ERROR, "currtid cannot handle views with no CTID");
288  rulelock = viewrel->rd_rules;
289  if (!rulelock)
290  elog(ERROR, "the view has no rules");
291  for (i = 0; i < rulelock->numLocks; i++)
292  {
293  rewrite = rulelock->rules[i];
294  if (rewrite->event == CMD_SELECT)
295  {
296  Query *query;
297  TargetEntry *tle;
298 
299  if (list_length(rewrite->actions) != 1)
300  elog(ERROR, "only one select rule is allowed in views");
301  query = (Query *) linitial(rewrite->actions);
302  tle = get_tle_by_resno(query->targetList, tididx + 1);
303  if (tle && tle->expr && IsA(tle->expr, Var))
304  {
305  Var *var = (Var *) tle->expr;
306  RangeTblEntry *rte;
307 
308  if (!IS_SPECIAL_VARNO(var->varno) &&
310  {
311  rte = rt_fetch(var->varno, query->rtable);
312  if (rte)
313  {
314  heap_close(viewrel, AccessShareLock);
316  }
317  }
318  }
319  break;
320  }
321  }
322  elog(ERROR, "currtid cannot handle this view");
323  return (Datum) 0;
324 }
325 
326 Datum
328 {
329  Oid reloid = PG_GETARG_OID(0);
332  Relation rel;
333  AclResult aclresult;
334  Snapshot snapshot;
335 
336  result = (ItemPointer) palloc(sizeof(ItemPointerData));
337  if (!reloid)
338  {
339  *result = Current_last_tid;
340  PG_RETURN_ITEMPOINTER(result);
341  }
342 
343  rel = heap_open(reloid, AccessShareLock);
344 
345  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
346  ACL_SELECT);
347  if (aclresult != ACLCHECK_OK)
348  aclcheck_error(aclresult, ACL_KIND_CLASS,
350 
351  if (rel->rd_rel->relkind == RELKIND_VIEW)
352  return currtid_for_view(rel, tid);
353 
354  ItemPointerCopy(tid, result);
355 
356  snapshot = RegisterSnapshot(GetLatestSnapshot());
357  heap_get_latest_tid(rel, snapshot, result);
358  UnregisterSnapshot(snapshot);
359 
361 
362  PG_RETURN_ITEMPOINTER(result);
363 }
364 
365 Datum
367 {
368  text *relname = PG_GETARG_TEXT_PP(0);
371  RangeVar *relrv;
372  Relation rel;
373  AclResult aclresult;
374  Snapshot snapshot;
375 
377  rel = heap_openrv(relrv, AccessShareLock);
378 
379  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
380  ACL_SELECT);
381  if (aclresult != ACLCHECK_OK)
382  aclcheck_error(aclresult, ACL_KIND_CLASS,
384 
385  if (rel->rd_rel->relkind == RELKIND_VIEW)
386  return currtid_for_view(rel, tid);
387 
388  result = (ItemPointer) palloc(sizeof(ItemPointerData));
389  ItemPointerCopy(tid, result);
390 
391  snapshot = RegisterSnapshot(GetLatestSnapshot());
392  heap_get_latest_tid(rel, snapshot, result);
393  UnregisterSnapshot(snapshot);
394 
396 
397  PG_RETURN_ITEMPOINTER(result);
398 }
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
Datum tidlt(PG_FUNCTION_ARGS)
Definition: tid.c:182
#define ItemPointerGetOffsetNumberNoCheck(pointer)
Definition: itemptr.h:86
Datum bttidcmp(PG_FUNCTION_ARGS)
Definition: tid.c:218
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
int numLocks
Definition: prs2lock.h:42
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define RelationGetDescr(relation)
Definition: rel.h:428
#define PG_GETARG_ITEMPOINTER(n)
Definition: tid.c:40
Oid GetUserId(void)
Definition: miscinit.c:284
#define LDELIM
Definition: tid.c:43
Datum tidsmaller(PG_FUNCTION_ARGS)
Definition: tid.c:236
#define PointerGetDatum(X)
Definition: postgres.h:562
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:84
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:359
char * pstrdup(const char *in)
Definition: mcxt.c:1077
StringInfoData * StringInfo
Definition: stringinfo.h:43
#define RDELIM
Definition: tid.c:44
#define PG_RETURN_INT32(x)
Definition: fmgr.h:314
#define AccessShareLock
Definition: lockdefs.h:36
void heap_get_latest_tid(Relation relation, Snapshot snapshot, ItemPointer tid)
Definition: heapam.c:2183
int errcode(int sqlerrcode)
Definition: elog.c:575
#define NTIDARGS
Definition: tid.c:46
AttrNumber varattno
Definition: primnodes.h:168
return result
Definition: formatting.c:1633
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:241
uint32 BlockNumber
Definition: block.h:31
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3023
#define heap_close(r, l)
Definition: heapam.h:97
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:329
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:163
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:379
int natts
Definition: tupdesc.h:73
List * targetList
Definition: parsenodes.h:138
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:49
static Datum currtid_for_view(Relation viewrel, ItemPointer tid)
Definition: tid.c:265
Datum tidsend(PG_FUNCTION_ARGS)
Definition: tid.c:146
#define TIDOID
Definition: pg_type.h:332
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:157
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Datum currtid_byreloid(PG_FUNCTION_ARGS)
Definition: tid.c:327
static ItemPointerData Current_last_tid
Definition: tid.c:251
#define PG_RETURN_ITEMPOINTER(x)
Definition: tid.c:41
static char * buf
Definition: pg_test_fsync.c:66
Datum tidrecv(PG_FUNCTION_ARGS)
Definition: tid.c:125
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
CmdType event
Definition: prs2lock.h:27
#define RelationGetRelationName(relation)
Definition: rel.h:436
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
RewriteRule ** rules
Definition: prs2lock.h:43
List * actions
Definition: prs2lock.h:29
void setLastTid(const ItemPointer tid)
Definition: tid.c:254
#define ereport(elevel, rest)
Definition: elog.h:122
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3202
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
Datum tidge(PG_FUNCTION_ARGS)
Definition: tid.c:209
Index varno
Definition: primnodes.h:166
Datum tidle(PG_FUNCTION_ARGS)
Definition: tid.c:191
Datum tidlarger(PG_FUNCTION_ARGS)
Definition: tid.c:227
AclResult
Definition: acl.h:170
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:372
#define ACL_SELECT
Definition: parsenodes.h:73
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1318
#define DELIM
Definition: tid.c:45
Datum tidin(PG_FUNCTION_ARGS)
Definition: tid.c:53
Expr * expr
Definition: primnodes.h:1368
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:322
RuleLock * rd_rules
Definition: rel.h:118
static int list_length(const List *l)
Definition: pg_list.h:89
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4422
Datum currtid_byrelname(PG_FUNCTION_ARGS)
Definition: tid.c:366
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
void pq_sendint(StringInfo buf, int i, int b)
Definition: pqformat.c:236
#define ItemPointerGetBlockNumberNoCheck(pointer)
Definition: itemptr.h:67
#define RELKIND_VIEW
Definition: pg_class.h:164
int i
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define NameStr(name)
Definition: c.h:499
Datum tidgt(PG_FUNCTION_ARGS)
Definition: tid.c:200
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Datum tidne(PG_FUNCTION_ARGS)
Definition: tid.c:173
Definition: c.h:439
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:448
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
#define elog
Definition: elog.h:219
Datum tidout(PG_FUNCTION_ARGS)
Definition: tid.c:105
#define RelationGetRelid(relation)
Definition: rel.h:416
Datum tideq(PG_FUNCTION_ARGS)
Definition: tid.c:164
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:586
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:105
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:139