~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to contrib/lo/lo.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      PostgreSQL type definitions for managed LargeObjects.
 
3
 *
 
4
 *      $PostgreSQL: pgsql/contrib/lo/lo.c,v 1.14 2003-11-29 19:51:35 pgsql Exp $
 
5
 *
 
6
 */
 
7
 
 
8
#include "postgres.h"
 
9
 
 
10
/* Required for largeobjects */
 
11
#include "libpq/libpq-fs.h"
 
12
#include "libpq/be-fsstubs.h"
 
13
 
 
14
/* Required for SPI */
 
15
#include "executor/spi.h"
 
16
 
 
17
/* Required for triggers */
 
18
#include "commands/trigger.h"
 
19
 
 
20
 
 
21
#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
 
22
 
 
23
 
 
24
/*
 
25
 *      This is the internal storage format for managed large objects
 
26
 *
 
27
 */
 
28
 
 
29
typedef Oid Blob;
 
30
 
 
31
/*
 
32
 *      Various forward declarations:
 
33
 */
 
34
 
 
35
Blob       *lo_in(char *str);   /* Create from String           */
 
36
char       *lo_out(Blob * addr);        /* Output oid as String         */
 
37
Oid                     lo_oid(Blob * addr);    /* Return oid as an oid         */
 
38
Blob       *lo(Oid oid);                /* Return Blob based on oid */
 
39
Datum           lo_manage(PG_FUNCTION_ARGS);            /* Trigger handler                 */
 
40
 
 
41
/*
 
42
 * This creates a large object, and sets its OID to the value in the
 
43
 * supplied string.
 
44
 *
 
45
 * If the string is empty, then a new LargeObject is created, and its oid
 
46
 * is placed in the resulting lo.
 
47
 */
 
48
Blob *
 
49
lo_in(char *str)
 
50
{
 
51
        Blob       *result;
 
52
        Oid                     oid;
 
53
        int                     count;
 
54
 
 
55
        if (strlen(str) > 0)
 
56
        {
 
57
                count = sscanf(str, "%u", &oid);
 
58
 
 
59
                if (count < 1)
 
60
                        ereport(ERROR,
 
61
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
62
                                         errmsg("error in parsing \"%s\"", str)));
 
63
 
 
64
                if (oid == InvalidOid)
 
65
                        ereport(ERROR,
 
66
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
67
                                         errmsg("illegal oid: \"%s\"", str)));
 
68
        }
 
69
        else
 
70
        {
 
71
                /*
 
72
                 * There is no Oid passed, so create a new one
 
73
                 */
 
74
                oid = DatumGetObjectId(DirectFunctionCall1(lo_creat,
 
75
                                                                   Int32GetDatum(INV_READ | INV_WRITE)));
 
76
                if (oid == InvalidOid)
 
77
                        /* internal error */
 
78
                        elog(ERROR, "InvalidOid returned from lo_creat");
 
79
        }
 
80
 
 
81
        result = (Blob *) palloc(sizeof(Blob));
 
82
 
 
83
        *result = oid;
 
84
 
 
85
        return (result);
 
86
}
 
87
 
 
88
/*
 
89
 * This simply outputs the Oid of the Blob as a string.
 
90
 */
 
91
char *
 
92
lo_out(Blob * addr)
 
93
{
 
94
        char       *result;
 
95
 
 
96
        if (addr == NULL)
 
97
                return (NULL);
 
98
 
 
99
        result = (char *) palloc(32);
 
100
        snprintf(result, 32, "%u", *addr);
 
101
        return (result);
 
102
}
 
103
 
 
104
/*
 
105
 * This function converts Blob to oid.
 
106
 *
 
107
 * eg: select lo_export(raster::oid,'/path/file') from table;
 
108
 *
 
109
 */
 
110
Oid
 
111
lo_oid(Blob * addr)
 
112
{
 
113
        if (addr == NULL)
 
114
                return InvalidOid;
 
115
        return (Oid) (*addr);
 
116
}
 
117
 
 
118
/*
 
119
 * This function is used so we can convert oid's to lo's
 
120
 *
 
121
 * ie:  insert into table values(lo_import('/path/file')::lo);
 
122
 *
 
123
 */
 
124
Blob *
 
125
lo(Oid oid)
 
126
{
 
127
        Blob       *result = (Blob *) palloc(sizeof(Blob));
 
128
 
 
129
        *result = oid;
 
130
        return (result);
 
131
}
 
132
 
 
133
/*
 
134
 * This handles the trigger that protects us from orphaned large objects
 
135
 */
 
136
PG_FUNCTION_INFO_V1(lo_manage);
 
137
 
 
138
Datum
 
139
lo_manage(PG_FUNCTION_ARGS)
 
140
{
 
141
        TriggerData *trigdata = (TriggerData *) fcinfo->context;
 
142
        int                     attnum;                 /* attribute number to monitor  */
 
143
        char      **args;                       /* Args containing attr name    */
 
144
        TupleDesc       tupdesc;                /* Tuple Descriptor                             */
 
145
        HeapTuple       rettuple;               /* Tuple to be returned                 */
 
146
        bool            isdelete;               /* are we deleting?                             */
 
147
        HeapTuple       newtuple = NULL;        /* The new value for tuple              */
 
148
        HeapTuple       trigtuple;              /* The original value of tuple  */
 
149
 
 
150
        if (!CALLED_AS_TRIGGER(fcinfo))
 
151
                /* internal error */
 
152
                elog(ERROR, "not fired by trigger manager");
 
153
 
 
154
        /*
 
155
         * Fetch some values from trigdata
 
156
         */
 
157
        newtuple = trigdata->tg_newtuple;
 
158
        trigtuple = trigdata->tg_trigtuple;
 
159
        tupdesc = trigdata->tg_relation->rd_att;
 
160
        args = trigdata->tg_trigger->tgargs;
 
161
 
 
162
        /* tuple to return to Executor */
 
163
        if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
 
164
                rettuple = newtuple;
 
165
        else
 
166
                rettuple = trigtuple;
 
167
 
 
168
        /* Are we deleting the row? */
 
169
        isdelete = TRIGGER_FIRED_BY_DELETE(trigdata->tg_event);
 
170
 
 
171
        /* Get the column were interested in */
 
172
        attnum = SPI_fnumber(tupdesc, args[0]);
 
173
 
 
174
        /*
 
175
         * Handle updates
 
176
         *
 
177
         * Here, if the value of the monitored attribute changes, then the large
 
178
         * object associated with the original value is unlinked.
 
179
         */
 
180
        if (newtuple != NULL)
 
181
        {
 
182
                char       *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
 
183
                char       *newv = SPI_getvalue(newtuple, tupdesc, attnum);
 
184
 
 
185
                if (orig != NULL && (newv == NULL || strcmp(orig, newv)))
 
186
                        DirectFunctionCall1(lo_unlink,
 
187
                                                                ObjectIdGetDatum(atooid(orig)));
 
188
 
 
189
                if (newv)
 
190
                        pfree(newv);
 
191
                if (orig)
 
192
                        pfree(orig);
 
193
        }
 
194
 
 
195
        /*
 
196
         * Handle deleting of rows
 
197
         *
 
198
         * Here, we unlink the large object associated with the managed attribute
 
199
         *
 
200
         */
 
201
        if (isdelete)
 
202
        {
 
203
                char       *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
 
204
 
 
205
                if (orig != NULL)
 
206
                {
 
207
                        DirectFunctionCall1(lo_unlink,
 
208
                                                                ObjectIdGetDatum(atooid(orig)));
 
209
 
 
210
                        pfree(orig);
 
211
                }
 
212
        }
 
213
 
 
214
        return PointerGetDatum(rettuple);
 
215
}