2 * PostgreSQL type definitions for managed LargeObjects.
4 * $PostgreSQL: pgsql/contrib/lo/lo.c,v 1.14 2003/11/29 19:51:35 pgsql Exp $
10 /* Required for largeobjects */
11 #include "libpq/libpq-fs.h"
12 #include "libpq/be-fsstubs.h"
14 /* Required for SPI */
15 #include "executor/spi.h"
17 /* Required for triggers */
18 #include "commands/trigger.h"
21 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
25 * This is the internal storage format for managed large objects
32 * Various forward declarations:
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 */
42 * This creates a large object, and sets its OID to the value in the
45 * If the string is empty, then a new LargeObject is created, and its oid
46 * is placed in the resulting lo.
57 count = sscanf(str, "%u", &oid);
61 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
62 errmsg("error in parsing \"%s\"", str)));
64 if (oid == InvalidOid)
66 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
67 errmsg("illegal oid: \"%s\"", str)));
72 * There is no Oid passed, so create a new one
74 oid = DatumGetObjectId(DirectFunctionCall1(lo_creat,
75 Int32GetDatum(INV_READ | INV_WRITE)));
76 if (oid == InvalidOid)
78 elog(ERROR, "InvalidOid returned from lo_creat");
81 result = (Blob *) palloc(sizeof(Blob));
89 * This simply outputs the Oid of the Blob as a string.
99 result = (char *) palloc(32);
100 snprintf(result, 32, "%u", *addr);
105 * This function converts Blob to oid.
107 * eg: select lo_export(raster::oid,'/path/file') from table;
115 return (Oid) (*addr);
119 * This function is used so we can convert oid's to lo's
121 * ie: insert into table values(lo_import('/path/file')::lo);
127 Blob *result = (Blob *) palloc(sizeof(Blob));
134 * This handles the trigger that protects us from orphaned large objects
136 PG_FUNCTION_INFO_V1(lo_manage);
139 lo_manage(PG_FUNCTION_ARGS)
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 */
150 if (!CALLED_AS_TRIGGER(fcinfo))
152 elog(ERROR, "not fired by trigger manager");
155 * Fetch some values from trigdata
157 newtuple = trigdata->tg_newtuple;
158 trigtuple = trigdata->tg_trigtuple;
159 tupdesc = trigdata->tg_relation->rd_att;
160 args = trigdata->tg_trigger->tgargs;
162 /* tuple to return to Executor */
163 if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
166 rettuple = trigtuple;
168 /* Are we deleting the row? */
169 isdelete = TRIGGER_FIRED_BY_DELETE(trigdata->tg_event);
171 /* Get the column were interested in */
172 attnum = SPI_fnumber(tupdesc, args[0]);
177 * Here, if the value of the monitored attribute changes, then the large
178 * object associated with the original value is unlinked.
180 if (newtuple != NULL)
182 char *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
183 char *newv = SPI_getvalue(newtuple, tupdesc, attnum);
185 if (orig != NULL && (newv == NULL || strcmp(orig, newv)))
186 DirectFunctionCall1(lo_unlink,
187 ObjectIdGetDatum(atooid(orig)));
196 * Handle deleting of rows
198 * Here, we unlink the large object associated with the managed attribute
203 char *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
207 DirectFunctionCall1(lo_unlink,
208 ObjectIdGetDatum(atooid(orig)));
214 return PointerGetDatum(rettuple);