PostgreSQL Source Code: src/backend/utils/adt/tid.c Source File

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

AltStyle によって変換されたページ (->オリジナル) /