Don't use 'return' where you should use 'PG_RETURN_xxx'.
[PostgreSQL.git] / src / backend / utils / adt / tid.c
blob5bb166dcd37ef7525f2cceafa4bc2a891a94a7b8
1 /*-------------------------------------------------------------------------
3 * tid.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 * NOTES
14 * input routine largely stolen from boxin().
16 *-------------------------------------------------------------------------
18 #include "postgres.h"
20 #include <math.h>
21 #include <limits.h>
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)
41 #define LDELIM '('
42 #define RDELIM ')'
43 #define DELIM ','
44 #define NTIDARGS 2
46 /* ----------------------------------------------------------------
47 * tidin
48 * ----------------------------------------------------------------
50 Datum
51 tidin(PG_FUNCTION_ARGS)
53 char *str = PG_GETARG_CSTRING(0);
54 char *p,
55 *coord[NTIDARGS];
56 int i;
57 ItemPointer result;
58 BlockNumber blockNumber;
59 OffsetNumber offsetNumber;
60 char *badp;
61 int hold_offset;
63 for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
64 if (*p == DELIM || (*p == LDELIM && !i))
65 coord[i++] = p + 1;
67 if (i < NTIDARGS)
68 ereport(ERROR,
69 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
70 errmsg("invalid input syntax for type tid: \"%s\"",
71 str)));
73 errno = 0;
74 blockNumber = strtoul(coord[0], &badp, 10);
75 if (errno || *badp != DELIM)
76 ereport(ERROR,
77 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
78 errmsg("invalid input syntax for type tid: \"%s\"",
79 str)));
81 hold_offset = strtol(coord[1], &badp, 10);
82 if (errno || *badp != RDELIM ||
83 hold_offset > USHRT_MAX || hold_offset < 0)
84 ereport(ERROR,
85 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86 errmsg("invalid input syntax for type tid: \"%s\"",
87 str)));
89 offsetNumber = hold_offset;
91 result = (ItemPointer) palloc(sizeof(ItemPointerData));
93 ItemPointerSet(result, blockNumber, offsetNumber);
95 PG_RETURN_ITEMPOINTER(result);
98 /* ----------------------------------------------------------------
99 * tidout
100 * ----------------------------------------------------------------
102 Datum
103 tidout(PG_FUNCTION_ARGS)
105 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
106 BlockNumber blockNumber;
107 OffsetNumber offsetNumber;
108 char buf[32];
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
122 Datum
123 tidrecv(PG_FUNCTION_ARGS)
125 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
126 ItemPointer result;
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
143 Datum
144 tidsend(PG_FUNCTION_ARGS)
146 ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
147 BlockId blockId;
148 BlockNumber blockNumber;
149 OffsetNumber offsetNumber;
150 StringInfoData buf;
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 /*****************************************************************************
163 * PUBLIC ROUTINES *
164 *****************************************************************************/
166 Datum
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);
175 Datum
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);
184 Datum
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);
193 Datum
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);
202 Datum
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);
211 Datum
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);
220 Datum
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));
229 Datum
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);
238 Datum
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};
256 void
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.
267 static Datum
268 currtid_for_view(Relation viewrel, ItemPointer tid)
270 TupleDesc att = RelationGetDescr(viewrel);
271 RuleLock *rulelock;
272 RewriteRule *rewrite;
273 int i,
274 natts = att->natts,
275 tididx = -1;
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");
283 tididx = i;
284 break;
287 if (tididx < 0)
288 elog(ERROR, "currtid cannot handle views with no CTID");
289 rulelock = viewrel->rd_rules;
290 if (!rulelock)
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)
297 Query *query;
298 TargetEntry *tle;
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;
307 RangeTblEntry *rte;
309 if (var->varno > 0 && var->varno < INNER &&
310 var->varattno == SelfItemPointerAttributeNumber)
312 rte = rt_fetch(var->varno, query->rtable);
313 if (rte)
315 heap_close(viewrel, AccessShareLock);
316 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
320 break;
323 elog(ERROR, "currtid cannot handle this view");
324 return (Datum) 0;
327 Datum
328 currtid_byreloid(PG_FUNCTION_ARGS)
330 Oid reloid = PG_GETARG_OID(0);
331 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
332 ItemPointer result;
333 Relation rel;
334 AclResult aclresult;
336 result = (ItemPointer) palloc(sizeof(ItemPointerData));
337 if (!reloid)
339 *result = Current_last_tid;
340 PG_RETURN_ITEMPOINTER(result);
343 rel = heap_open(reloid, AccessShareLock);
345 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
346 ACL_SELECT);
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);
362 Datum
363 currtid_byrelname(PG_FUNCTION_ARGS)
365 text *relname = PG_GETARG_TEXT_P(0);
366 ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
367 ItemPointer result;
368 RangeVar *relrv;
369 Relation rel;
370 AclResult aclresult;
372 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
373 rel = heap_openrv(relrv, AccessShareLock);
375 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
376 ACL_SELECT);
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);