]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/tid.c
Fix tid to in/out as unsigned.
[postgresql] / src / backend / utils / adt / tid.c
1 /*-------------------------------------------------------------------------
2  *
3  * tid.c
4  *        Functions for the built-in type tuple id
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.32 2002/07/16 17:55:25 momjian Exp $
12  *
13  * NOTES
14  *        input routine largely stolen from boxin().
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include "postgres.h"
20
21 #include <errno.h>
22 #include <math.h>
23 #include <limits.h>
24
25 #include "access/heapam.h"
26 #include "catalog/namespace.h"
27 #include "utils/builtins.h"
28 #include "catalog/pg_type.h"
29
30 #define DatumGetItemPointer(X)   ((ItemPointer) DatumGetPointer(X))
31 #define ItemPointerGetDatum(X)   PointerGetDatum(X)
32 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
33 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
34
35 #define LDELIM                  '('
36 #define RDELIM                  ')'
37 #define DELIM                   ','
38 #define NTIDARGS                2
39
40 /* ----------------------------------------------------------------
41  *              tidin
42  * ----------------------------------------------------------------
43  */
44 Datum
45 tidin(PG_FUNCTION_ARGS)
46 {
47         char       *str = PG_GETARG_CSTRING(0);
48         char       *p,
49                            *coord[NTIDARGS];
50         int                     i;
51         ItemPointer result;
52         BlockNumber blockNumber;
53         OffsetNumber offsetNumber;
54         char       *badp;
55         int                     hold_offset;
56
57         for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
58                 if (*p == DELIM || (*p == LDELIM && !i))
59                         coord[i++] = p + 1;
60
61         if (i < NTIDARGS)
62                 elog(ERROR, "invalid tid format: '%s'", str);
63
64         errno = 0;
65         blockNumber = strtoul(coord[0], &badp, 10);
66         if (errno || *badp != DELIM)
67                 elog(ERROR, "tidin: invalid value.");
68
69         hold_offset = strtol(coord[1], &badp, 10);
70         if (errno || *badp != RDELIM ||
71                 hold_offset > USHRT_MAX || hold_offset < 0)
72                 elog(ERROR, "tidin: invalid value.");
73         offsetNumber = hold_offset;
74
75         result = (ItemPointer) palloc(sizeof(ItemPointerData));
76
77         ItemPointerSet(result, blockNumber, offsetNumber);
78
79         PG_RETURN_ITEMPOINTER(result);
80 }
81
82 /* ----------------------------------------------------------------
83  *              tidout
84  * ----------------------------------------------------------------
85  */
86 Datum
87 tidout(PG_FUNCTION_ARGS)
88 {
89         ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
90         BlockId         blockId;
91         BlockNumber blockNumber;
92         OffsetNumber offsetNumber;
93         char            buf[32];
94         static char *invalidTid = "()";
95
96         if (!ItemPointerIsValid(itemPtr))
97                 PG_RETURN_CSTRING(pstrdup(invalidTid));
98
99         blockId = &(itemPtr->ip_blkid);
100
101         blockNumber = BlockIdGetBlockNumber(blockId);
102         offsetNumber = itemPtr->ip_posid;
103
104         sprintf(buf, "(%u,%u)", blockNumber, offsetNumber);
105
106         PG_RETURN_CSTRING(pstrdup(buf));
107 }
108
109 /*****************************************************************************
110  *       PUBLIC ROUTINES                                                                                                                 *
111  *****************************************************************************/
112
113 Datum
114 tideq(PG_FUNCTION_ARGS)
115 {
116         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
117         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
118
119         PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
120                                    BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
121                                    arg1->ip_posid == arg2->ip_posid);
122 }
123
124 #ifdef NOT_USED
125 Datum
126 tidne(PG_FUNCTION_ARGS)
127 {
128         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
129         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
130
131         PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
132                                    BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
133                                    arg1->ip_posid != arg2->ip_posid);
134 }
135 #endif
136
137 /*
138  *      Functions to get latest tid of a specified tuple.
139  *
140  *      Maybe these implementations should be moved to another place
141  */
142
143 static ItemPointerData Current_last_tid = {{0, 0}, 0};
144
145 void
146 setLastTid(const ItemPointer tid)
147 {
148         Current_last_tid = *tid;
149 }
150
151 /*
152  *      Handle CTIDs of views.
153  *              CTID should be defined in the view and it must
154  *              correspond to the CTID of a base relation.
155  */
156 static Datum
157 currtid_for_view(Relation viewrel, ItemPointer tid) 
158 {
159         TupleDesc       att = RelationGetDescr(viewrel);
160         RuleLock        *rulelock;
161         RewriteRule     *rewrite;
162         int     i, natts = att->natts, tididx = -1;
163
164         for (i = 0; i < natts ; i++)
165         {
166                 if (strcasecmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
167                 {
168                         if (att->attrs[i]->atttypid != TIDOID)
169                                 elog(ERROR, "ctid isn't of type TID");
170                         tididx = i;
171                 }
172         }
173         if (tididx < 0)
174                 elog(ERROR, "currtid can't handle views with no CTID");
175         if (rulelock = viewrel->rd_rules, !rulelock)
176                 elog(ERROR, "the view has no rules");
177         for (i = 0; i < rulelock->numLocks; i++)
178         {
179                 rewrite = rulelock->rules[i];
180                 if (rewrite->event == CMD_SELECT)
181                 {
182                         Query   *query;
183                         TargetEntry *tle;
184
185                         if (length(rewrite->actions) != 1)
186                                 elog(ERROR, "only one select rule is allowed in views");
187                         query = (Query *) lfirst(rewrite->actions);
188                         tle = (TargetEntry *) nth(tididx, query->targetList);
189                         if (tle && tle->expr && nodeTag(tle->expr) == T_Var)
190                         {
191                                 Var *var = (Var *) tle->expr;
192                                 RangeTblEntry *rte;
193                                 if (var->varno > 0 && var->varno < INNER && var->varattno == SelfItemPointerAttributeNumber)
194                                 {
195                                         rte = (RangeTblEntry *) nth(var->varno - 1, query->rtable);
196                                         if (rte)
197                                         {
198                                                 heap_close(viewrel, AccessShareLock);
199                                                 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
200                                         }
201                                 }
202                         }
203                         break;
204                 }
205         }
206         elog(ERROR, "currtid can't handle this view");
207         return (Datum) 0;
208 }
209
210 Datum
211 currtid_byreloid(PG_FUNCTION_ARGS)
212 {
213         Oid                     reloid = PG_GETARG_OID(0);
214         ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
215         ItemPointer result;
216         Relation        rel;
217
218         result = (ItemPointer) palloc(sizeof(ItemPointerData));
219         if (!reloid)
220         {
221                 *result = Current_last_tid;
222                 PG_RETURN_ITEMPOINTER(result);
223         }
224
225         rel = heap_open(reloid, AccessShareLock);
226         if (rel->rd_rel->relkind == RELKIND_VIEW)
227                 return currtid_for_view(rel, tid);
228
229         ItemPointerCopy(tid, result);
230         heap_get_latest_tid(rel, SnapshotNow, result);
231
232         heap_close(rel, AccessShareLock);
233
234         PG_RETURN_ITEMPOINTER(result);
235 }
236
237 Datum
238 currtid_byrelname(PG_FUNCTION_ARGS)
239 {
240         text       *relname = PG_GETARG_TEXT_P(0);
241         ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
242         ItemPointer result;
243         RangeVar   *relrv;
244         Relation        rel;
245
246         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
247                                                                                                                 "currtid_byrelname"));
248         rel = heap_openrv(relrv, AccessShareLock);
249         if (rel->rd_rel->relkind == RELKIND_VIEW)
250                 return currtid_for_view(rel, tid);
251
252         result = (ItemPointer) palloc(sizeof(ItemPointerData));
253         ItemPointerCopy(tid, result);
254
255         heap_get_latest_tid(rel, SnapshotNow, result);
256
257         heap_close(rel, AccessShareLock);
258
259         PG_RETURN_ITEMPOINTER(result);
260 }