~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/tid.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * tid.c
 
4
 *        Functions for the built-in type tuple id
 
5
 *
 
6
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL$
 
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
}