OSDN Git Service

bdc9307bc298f2877c08af4c9c168da327907172
[pg-rex/syncrep.git] / contrib / lo / lo.c
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 }