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
);