OSDN Git Service

Pgindent run for 8.0.
[pg-rex/syncrep.git] / 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-2004, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/utils/adt/tid.c,v 1.47 2004/08/29 05:06:49 momjian Exp $
12  *
13  * NOTES
14  *        input routine largely stolen from boxin().
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19
20 #include <errno.h>
21 #include <math.h>
22 #include <limits.h>
23
24 #include "access/heapam.h"
25 #include "catalog/namespace.h"
26 #include "catalog/pg_type.h"
27 #include "libpq/pqformat.h"
28 #include "parser/parsetree.h"
29 #include "utils/builtins.h"
30
31
32 #define DatumGetItemPointer(X)   ((ItemPointer) DatumGetPointer(X))
33 #define ItemPointerGetDatum(X)   PointerGetDatum(X)
34 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
35 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
36
37 #define LDELIM                  '('
38 #define RDELIM                  ')'
39 #define DELIM                   ','
40 #define NTIDARGS                2
41
42 /* ----------------------------------------------------------------
43  *              tidin
44  * ----------------------------------------------------------------
45  */
46 Datum
47 tidin(PG_FUNCTION_ARGS)
48 {
49         char       *str = PG_GETARG_CSTRING(0);
50         char       *p,
51                            *coord[NTIDARGS];
52         int                     i;
53         ItemPointer result;
54         BlockNumber blockNumber;
55         OffsetNumber offsetNumber;
56         char       *badp;
57         int                     hold_offset;
58
59         for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
60                 if (*p == DELIM || (*p == LDELIM && !i))
61                         coord[i++] = p + 1;
62
63         if (i < NTIDARGS)
64                 ereport(ERROR,
65                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
66                                  errmsg("invalid input syntax for type tid: \"%s\"",
67                                                 str)));
68
69         errno = 0;
70         blockNumber = strtoul(coord[0], &badp, 10);
71         if (errno || *badp != DELIM)
72                 ereport(ERROR,
73                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
74                                  errmsg("invalid input syntax for type tid: \"%s\"",
75                                                 str)));
76
77         hold_offset = strtol(coord[1], &badp, 10);
78         if (errno || *badp != RDELIM ||
79                 hold_offset > USHRT_MAX || hold_offset < 0)
80                 ereport(ERROR,
81                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
82                                  errmsg("invalid input syntax for type tid: \"%s\"",
83                                                 str)));
84
85         offsetNumber = hold_offset;
86
87         result = (ItemPointer) palloc(sizeof(ItemPointerData));
88
89         ItemPointerSet(result, blockNumber, offsetNumber);
90
91         PG_RETURN_ITEMPOINTER(result);
92 }
93
94 /* ----------------------------------------------------------------
95  *              tidout
96  * ----------------------------------------------------------------
97  */
98 Datum
99 tidout(PG_FUNCTION_ARGS)
100 {
101         ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
102         BlockId         blockId;
103         BlockNumber blockNumber;
104         OffsetNumber offsetNumber;
105         char            buf[32];
106
107         if (!ItemPointerIsValid(itemPtr))
108                 PG_RETURN_CSTRING(pstrdup("()"));
109
110         blockId = &(itemPtr->ip_blkid);
111         blockNumber = BlockIdGetBlockNumber(blockId);
112         offsetNumber = itemPtr->ip_posid;
113
114         snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
115
116         PG_RETURN_CSTRING(pstrdup(buf));
117 }
118
119 /*
120  *              tidrecv                 - converts external binary format to tid
121  */
122 Datum
123 tidrecv(PG_FUNCTION_ARGS)
124 {
125         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
126         ItemPointer result;
127         BlockNumber blockNumber;
128         OffsetNumber offsetNumber;
129
130         blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
131         offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
132
133         result = (ItemPointer) palloc(sizeof(ItemPointerData));
134
135         ItemPointerSet(result, blockNumber, offsetNumber);
136
137         PG_RETURN_ITEMPOINTER(result);
138 }
139
140 /*
141  *              tidsend                 - converts tid to binary format
142  */
143 Datum
144 tidsend(PG_FUNCTION_ARGS)
145 {
146         ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
147         BlockId         blockId;
148         BlockNumber blockNumber;
149         OffsetNumber offsetNumber;
150         StringInfoData buf;
151
152         blockId = &(itemPtr->ip_blkid);
153         blockNumber = BlockIdGetBlockNumber(blockId);
154         offsetNumber = itemPtr->ip_posid;
155
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));
160 }
161
162 /*****************************************************************************
163  *       PUBLIC ROUTINES                                                                                                                 *
164  *****************************************************************************/
165
166 Datum
167 tideq(PG_FUNCTION_ARGS)
168 {
169         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
170         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
171
172         PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) ==
173                                    BlockIdGetBlockNumber(&(arg2->ip_blkid)) &&
174                                    arg1->ip_posid == arg2->ip_posid);
175 }
176
177 #ifdef NOT_USED
178 Datum
179 tidne(PG_FUNCTION_ARGS)
180 {
181         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
182         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
183
184         PG_RETURN_BOOL(BlockIdGetBlockNumber(&(arg1->ip_blkid)) !=
185                                    BlockIdGetBlockNumber(&(arg2->ip_blkid)) ||
186                                    arg1->ip_posid != arg2->ip_posid);
187 }
188 #endif
189
190 /*
191  *      Functions to get latest tid of a specified tuple.
192  *
193  *      Maybe these implementations should be moved to another place
194  */
195
196 static ItemPointerData Current_last_tid = {{0, 0}, 0};
197
198 void
199 setLastTid(const ItemPointer tid)
200 {
201         Current_last_tid = *tid;
202 }
203
204 /*
205  *      Handle CTIDs of views.
206  *              CTID should be defined in the view and it must
207  *              correspond to the CTID of a base relation.
208  */
209 static Datum
210 currtid_for_view(Relation viewrel, ItemPointer tid)
211 {
212         TupleDesc       att = RelationGetDescr(viewrel);
213         RuleLock   *rulelock;
214         RewriteRule *rewrite;
215         int                     i,
216                                 natts = att->natts,
217                                 tididx = -1;
218
219         for (i = 0; i < natts; i++)
220         {
221                 if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
222                 {
223                         if (att->attrs[i]->atttypid != TIDOID)
224                                 elog(ERROR, "ctid isn't of type TID");
225                         tididx = i;
226                         break;
227                 }
228         }
229         if (tididx < 0)
230                 elog(ERROR, "currtid cannot handle views with no CTID");
231         rulelock = viewrel->rd_rules;
232         if (!rulelock)
233                 elog(ERROR, "the view has no rules");
234         for (i = 0; i < rulelock->numLocks; i++)
235         {
236                 rewrite = rulelock->rules[i];
237                 if (rewrite->event == CMD_SELECT)
238                 {
239                         Query      *query;
240                         TargetEntry *tle;
241
242                         if (list_length(rewrite->actions) != 1)
243                                 elog(ERROR, "only one select rule is allowed in views");
244                         query = (Query *) linitial(rewrite->actions);
245                         tle = get_tle_by_resno(query->targetList, tididx + 1);
246                         if (tle && tle->expr && IsA(tle->expr, Var))
247                         {
248                                 Var                *var = (Var *) tle->expr;
249                                 RangeTblEntry *rte;
250
251                                 if (var->varno > 0 && var->varno < INNER &&
252                                         var->varattno == SelfItemPointerAttributeNumber)
253                                 {
254                                         rte = rt_fetch(var->varno, query->rtable);
255                                         if (rte)
256                                         {
257                                                 heap_close(viewrel, AccessShareLock);
258                                                 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
259                                         }
260                                 }
261                         }
262                         break;
263                 }
264         }
265         elog(ERROR, "currtid cannot handle this view");
266         return (Datum) 0;
267 }
268
269 Datum
270 currtid_byreloid(PG_FUNCTION_ARGS)
271 {
272         Oid                     reloid = PG_GETARG_OID(0);
273         ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
274         ItemPointer result;
275         Relation        rel;
276
277         result = (ItemPointer) palloc(sizeof(ItemPointerData));
278         if (!reloid)
279         {
280                 *result = Current_last_tid;
281                 PG_RETURN_ITEMPOINTER(result);
282         }
283
284         rel = heap_open(reloid, AccessShareLock);
285         if (rel->rd_rel->relkind == RELKIND_VIEW)
286                 return currtid_for_view(rel, tid);
287
288         ItemPointerCopy(tid, result);
289         heap_get_latest_tid(rel, SnapshotNow, result);
290
291         heap_close(rel, AccessShareLock);
292
293         PG_RETURN_ITEMPOINTER(result);
294 }
295
296 Datum
297 currtid_byrelname(PG_FUNCTION_ARGS)
298 {
299         text       *relname = PG_GETARG_TEXT_P(0);
300         ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
301         ItemPointer result;
302         RangeVar   *relrv;
303         Relation        rel;
304
305         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
306                                                                                                    "currtid_byrelname"));
307         rel = heap_openrv(relrv, AccessShareLock);
308         if (rel->rd_rel->relkind == RELKIND_VIEW)
309                 return currtid_for_view(rel, tid);
310
311         result = (ItemPointer) palloc(sizeof(ItemPointerData));
312         ItemPointerCopy(tid, result);
313
314         heap_get_latest_tid(rel, SnapshotNow, result);
315
316         heap_close(rel, AccessShareLock);
317
318         PG_RETURN_ITEMPOINTER(result);
319 }