1
/*-------------------------------------------------------------------------
4
* Functions for the built-in type tuple id
6
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
14
* input routine largely stolen from boxin().
16
*-------------------------------------------------------------------------
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/tqual.h"
36
#define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
37
#define ItemPointerGetDatum(X) PointerGetDatum(X)
38
#define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
39
#define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
46
/* ----------------------------------------------------------------
48
* ----------------------------------------------------------------
51
tidin(PG_FUNCTION_ARGS)
53
char *str = PG_GETARG_CSTRING(0);
58
BlockNumber blockNumber;
59
OffsetNumber offsetNumber;
63
for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
64
if (*p == DELIM || (*p == LDELIM && !i))
69
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
70
errmsg("invalid input syntax for type tid: \"%s\"",
74
blockNumber = strtoul(coord[0], &badp, 10);
75
if (errno || *badp != DELIM)
77
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
78
errmsg("invalid input syntax for type tid: \"%s\"",
81
hold_offset = strtol(coord[1], &badp, 10);
82
if (errno || *badp != RDELIM ||
83
hold_offset > USHRT_MAX || hold_offset < 0)
85
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86
errmsg("invalid input syntax for type tid: \"%s\"",
89
offsetNumber = hold_offset;
91
result = (ItemPointer) palloc(sizeof(ItemPointerData));
93
ItemPointerSet(result, blockNumber, offsetNumber);
95
PG_RETURN_ITEMPOINTER(result);
98
/* ----------------------------------------------------------------
100
* ----------------------------------------------------------------
103
tidout(PG_FUNCTION_ARGS)
105
ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
106
BlockNumber blockNumber;
107
OffsetNumber offsetNumber;
110
blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
111
offsetNumber = itemPtr->ip_posid;
113
/* Perhaps someday we should output this as a record. */
114
snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
116
PG_RETURN_CSTRING(pstrdup(buf));
120
* tidrecv - converts external binary format to tid
123
tidrecv(PG_FUNCTION_ARGS)
125
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
127
BlockNumber blockNumber;
128
OffsetNumber offsetNumber;
130
blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
131
offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
133
result = (ItemPointer) palloc(sizeof(ItemPointerData));
135
ItemPointerSet(result, blockNumber, offsetNumber);
137
PG_RETURN_ITEMPOINTER(result);
141
* tidsend - converts tid to binary format
144
tidsend(PG_FUNCTION_ARGS)
146
ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
148
BlockNumber blockNumber;
149
OffsetNumber offsetNumber;
152
blockId = &(itemPtr->ip_blkid);
153
blockNumber = BlockIdGetBlockNumber(blockId);
154
offsetNumber = itemPtr->ip_posid;
156
pq_begintypsend(&buf);
157
pq_sendint(&buf, blockNumber, sizeof(blockNumber));
158
pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
159
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
162
/*****************************************************************************
164
*****************************************************************************/
167
tideq(PG_FUNCTION_ARGS)
169
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
170
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
172
PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
176
tidne(PG_FUNCTION_ARGS)
178
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
179
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
181
PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
185
tidlt(PG_FUNCTION_ARGS)
187
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
188
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
190
PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
194
tidle(PG_FUNCTION_ARGS)
196
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
197
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
199
PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
203
tidgt(PG_FUNCTION_ARGS)
205
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
206
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
208
PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
212
tidge(PG_FUNCTION_ARGS)
214
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
215
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
217
PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
221
bttidcmp(PG_FUNCTION_ARGS)
223
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
224
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
226
PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
230
tidlarger(PG_FUNCTION_ARGS)
232
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
233
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
235
PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
239
tidsmaller(PG_FUNCTION_ARGS)
241
ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
242
ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
244
PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
249
* Functions to get latest tid of a specified tuple.
251
* Maybe these implementations should be moved to another place
254
static ItemPointerData Current_last_tid = {{0, 0}, 0};
257
setLastTid(const ItemPointer tid)
259
Current_last_tid = *tid;
263
* Handle CTIDs of views.
264
* CTID should be defined in the view and it must
265
* correspond to the CTID of a base relation.
268
currtid_for_view(Relation viewrel, ItemPointer tid)
270
TupleDesc att = RelationGetDescr(viewrel);
272
RewriteRule *rewrite;
277
for (i = 0; i < natts; i++)
279
if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
281
if (att->attrs[i]->atttypid != TIDOID)
282
elog(ERROR, "ctid isn't of type TID");
288
elog(ERROR, "currtid cannot handle views with no CTID");
289
rulelock = viewrel->rd_rules;
291
elog(ERROR, "the view has no rules");
292
for (i = 0; i < rulelock->numLocks; i++)
294
rewrite = rulelock->rules[i];
295
if (rewrite->event == CMD_SELECT)
300
if (list_length(rewrite->actions) != 1)
301
elog(ERROR, "only one select rule is allowed in views");
302
query = (Query *) linitial(rewrite->actions);
303
tle = get_tle_by_resno(query->targetList, tididx + 1);
304
if (tle && tle->expr && IsA(tle->expr, Var))
306
Var *var = (Var *) tle->expr;
309
if (var->varno > 0 && var->varno < INNER &&
310
var->varattno == SelfItemPointerAttributeNumber)
312
rte = rt_fetch(var->varno, query->rtable);
315
heap_close(viewrel, AccessShareLock);
316
return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
323
elog(ERROR, "currtid cannot handle this view");
328
currtid_byreloid(PG_FUNCTION_ARGS)
330
Oid reloid = PG_GETARG_OID(0);
331
ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
336
result = (ItemPointer) palloc(sizeof(ItemPointerData));
339
*result = Current_last_tid;
340
PG_RETURN_ITEMPOINTER(result);
343
rel = heap_open(reloid, AccessShareLock);
345
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
347
if (aclresult != ACLCHECK_OK)
348
aclcheck_error(aclresult, ACL_KIND_CLASS,
349
RelationGetRelationName(rel));
351
if (rel->rd_rel->relkind == RELKIND_VIEW)
352
return currtid_for_view(rel, tid);
354
ItemPointerCopy(tid, result);
355
heap_get_latest_tid(rel, SnapshotNow, result);
357
heap_close(rel, AccessShareLock);
359
PG_RETURN_ITEMPOINTER(result);
363
currtid_byrelname(PG_FUNCTION_ARGS)
365
text *relname = PG_GETARG_TEXT_P(0);
366
ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
372
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
373
rel = heap_openrv(relrv, AccessShareLock);
375
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
377
if (aclresult != ACLCHECK_OK)
378
aclcheck_error(aclresult, ACL_KIND_CLASS,
379
RelationGetRelationName(rel));
381
if (rel->rd_rel->relkind == RELKIND_VIEW)
382
return currtid_for_view(rel, tid);
384
result = (ItemPointer) palloc(sizeof(ItemPointerData));
385
ItemPointerCopy(tid, result);
387
heap_get_latest_tid(rel, SnapshotNow, result);
389
heap_close(rel, AccessShareLock);
391
PG_RETURN_ITEMPOINTER(result);