OSDN Git Service

Fix typo in sslmode documentation
[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-2011, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/utils/adt/tid.c
12  *
13  * NOTES
14  *        input routine largely stolen from boxin().
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19
20 #include <math.h>
21 #include <limits.h>
22
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"
34
35
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)
40
41 #define LDELIM                  '('
42 #define RDELIM                  ')'
43 #define DELIM                   ','
44 #define NTIDARGS                2
45
46 /* ----------------------------------------------------------------
47  *              tidin
48  * ----------------------------------------------------------------
49  */
50 Datum
51 tidin(PG_FUNCTION_ARGS)
52 {
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;
62
63         for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
64                 if (*p == DELIM || (*p == LDELIM && !i))
65                         coord[i++] = p + 1;
66
67         if (i < NTIDARGS)
68                 ereport(ERROR,
69                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
70                                  errmsg("invalid input syntax for type tid: \"%s\"",
71                                                 str)));
72
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)));
80
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)));
88
89         offsetNumber = hold_offset;
90
91         result = (ItemPointer) palloc(sizeof(ItemPointerData));
92
93         ItemPointerSet(result, blockNumber, offsetNumber);
94
95         PG_RETURN_ITEMPOINTER(result);
96 }
97
98 /* ----------------------------------------------------------------
99  *              tidout
100  * ----------------------------------------------------------------
101  */
102 Datum
103 tidout(PG_FUNCTION_ARGS)
104 {
105         ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
106         BlockNumber blockNumber;
107         OffsetNumber offsetNumber;
108         char            buf[32];
109
110         blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
111         offsetNumber = itemPtr->ip_posid;
112
113         /* Perhaps someday we should output this as a record. */
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(ItemPointerCompare(arg1, arg2) == 0);
173 }
174
175 Datum
176 tidne(PG_FUNCTION_ARGS)
177 {
178         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
179         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
180
181         PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
182 }
183
184 Datum
185 tidlt(PG_FUNCTION_ARGS)
186 {
187         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
188         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
189
190         PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
191 }
192
193 Datum
194 tidle(PG_FUNCTION_ARGS)
195 {
196         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
197         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
198
199         PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
200 }
201
202 Datum
203 tidgt(PG_FUNCTION_ARGS)
204 {
205         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
206         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
207
208         PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
209 }
210
211 Datum
212 tidge(PG_FUNCTION_ARGS)
213 {
214         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
215         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
216
217         PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
218 }
219
220 Datum
221 bttidcmp(PG_FUNCTION_ARGS)
222 {
223         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
224         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
225
226         PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
227 }
228
229 Datum
230 tidlarger(PG_FUNCTION_ARGS)
231 {
232         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
233         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
234
235         PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
236 }
237
238 Datum
239 tidsmaller(PG_FUNCTION_ARGS)
240 {
241         ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
242         ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
243
244         PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
245 }
246
247
248 /*
249  *      Functions to get latest tid of a specified tuple.
250  *
251  *      Maybe these implementations should be moved to another place
252  */
253
254 static ItemPointerData Current_last_tid = {{0, 0}, 0};
255
256 void
257 setLastTid(const ItemPointer tid)
258 {
259         Current_last_tid = *tid;
260 }
261
262 /*
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.
266  */
267 static Datum
268 currtid_for_view(Relation viewrel, ItemPointer tid)
269 {
270         TupleDesc       att = RelationGetDescr(viewrel);
271         RuleLock   *rulelock;
272         RewriteRule *rewrite;
273         int                     i,
274                                 natts = att->natts,
275                                 tididx = -1;
276
277         for (i = 0; i < natts; i++)
278         {
279                 if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
280                 {
281                         if (att->attrs[i]->atttypid != TIDOID)
282                                 elog(ERROR, "ctid isn't of type TID");
283                         tididx = i;
284                         break;
285                 }
286         }
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++)
293         {
294                 rewrite = rulelock->rules[i];
295                 if (rewrite->event == CMD_SELECT)
296                 {
297                         Query      *query;
298                         TargetEntry *tle;
299
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))
305                         {
306                                 Var                *var = (Var *) tle->expr;
307                                 RangeTblEntry *rte;
308
309                                 if (var->varno > 0 && var->varno < INNER &&
310                                         var->varattno == SelfItemPointerAttributeNumber)
311                                 {
312                                         rte = rt_fetch(var->varno, query->rtable);
313                                         if (rte)
314                                         {
315                                                 heap_close(viewrel, AccessShareLock);
316                                                 return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
317                                         }
318                                 }
319                         }
320                         break;
321                 }
322         }
323         elog(ERROR, "currtid cannot handle this view");
324         return (Datum) 0;
325 }
326
327 Datum
328 currtid_byreloid(PG_FUNCTION_ARGS)
329 {
330         Oid                     reloid = PG_GETARG_OID(0);
331         ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
332         ItemPointer result;
333         Relation        rel;
334         AclResult       aclresult;
335
336         result = (ItemPointer) palloc(sizeof(ItemPointerData));
337         if (!reloid)
338         {
339                 *result = Current_last_tid;
340                 PG_RETURN_ITEMPOINTER(result);
341         }
342
343         rel = heap_open(reloid, AccessShareLock);
344
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));
350
351         if (rel->rd_rel->relkind == RELKIND_VIEW)
352                 return currtid_for_view(rel, tid);
353
354         ItemPointerCopy(tid, result);
355         heap_get_latest_tid(rel, SnapshotNow, result);
356
357         heap_close(rel, AccessShareLock);
358
359         PG_RETURN_ITEMPOINTER(result);
360 }
361
362 Datum
363 currtid_byrelname(PG_FUNCTION_ARGS)
364 {
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;
371
372         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
373         rel = heap_openrv(relrv, AccessShareLock);
374
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));
380
381         if (rel->rd_rel->relkind == RELKIND_VIEW)
382                 return currtid_for_view(rel, tid);
383
384         result = (ItemPointer) palloc(sizeof(ItemPointerData));
385         ItemPointerCopy(tid, result);
386
387         heap_get_latest_tid(rel, SnapshotNow, result);
388
389         heap_close(rel, AccessShareLock);
390
391         PG_RETURN_ITEMPOINTER(result);
392 }