Header And Logo

PostgreSQL
| The world's most advanced open source database.

lo.c

Go to the documentation of this file.
00001 /*
00002  *  PostgreSQL definitions for managed Large Objects.
00003  *
00004  *  contrib/lo/lo.c
00005  *
00006  */
00007 
00008 #include "postgres.h"
00009 
00010 #include "commands/trigger.h"
00011 #include "executor/spi.h"
00012 #include "libpq/be-fsstubs.h"
00013 #include "utils/rel.h"
00014 
00015 
00016 PG_MODULE_MAGIC;
00017 
00018 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
00019 
00020 
00021 /* forward declarations */
00022 Datum       lo_manage(PG_FUNCTION_ARGS);
00023 
00024 
00025 /*
00026  * This is the trigger that protects us from orphaned large objects
00027  */
00028 PG_FUNCTION_INFO_V1(lo_manage);
00029 
00030 Datum
00031 lo_manage(PG_FUNCTION_ARGS)
00032 {
00033     TriggerData *trigdata = (TriggerData *) fcinfo->context;
00034     int         attnum;         /* attribute number to monitor  */
00035     char      **args;           /* Args containing attr name    */
00036     TupleDesc   tupdesc;        /* Tuple Descriptor             */
00037     HeapTuple   rettuple;       /* Tuple to be returned         */
00038     bool        isdelete;       /* are we deleting?             */
00039     HeapTuple   newtuple;       /* The new value for tuple      */
00040     HeapTuple   trigtuple;      /* The original value of tuple  */
00041 
00042     if (!CALLED_AS_TRIGGER(fcinfo))     /* internal error */
00043         elog(ERROR, "not fired by trigger manager");
00044 
00045     /*
00046      * Fetch some values from trigdata
00047      */
00048     newtuple = trigdata->tg_newtuple;
00049     trigtuple = trigdata->tg_trigtuple;
00050     tupdesc = trigdata->tg_relation->rd_att;
00051     args = trigdata->tg_trigger->tgargs;
00052 
00053     /* tuple to return to Executor */
00054     if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
00055         rettuple = newtuple;
00056     else
00057         rettuple = trigtuple;
00058 
00059     /* Are we deleting the row? */
00060     isdelete = TRIGGER_FIRED_BY_DELETE(trigdata->tg_event);
00061 
00062     /* Get the column we're interested in */
00063     attnum = SPI_fnumber(tupdesc, args[0]);
00064 
00065     if (attnum <= 0)
00066         elog(ERROR, "column \"%s\" does not exist", args[0]);
00067 
00068     /*
00069      * Handle updates
00070      *
00071      * Here, if the value of the monitored attribute changes, then the large
00072      * object associated with the original value is unlinked.
00073      */
00074     if (newtuple != NULL)
00075     {
00076         char       *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
00077         char       *newv = SPI_getvalue(newtuple, tupdesc, attnum);
00078 
00079         if (orig != NULL && (newv == NULL || strcmp(orig, newv) != 0))
00080             DirectFunctionCall1(lo_unlink,
00081                                 ObjectIdGetDatum(atooid(orig)));
00082 
00083         if (newv)
00084             pfree(newv);
00085         if (orig)
00086             pfree(orig);
00087     }
00088 
00089     /*
00090      * Handle deleting of rows
00091      *
00092      * Here, we unlink the large object associated with the managed attribute
00093      */
00094     if (isdelete)
00095     {
00096         char       *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
00097 
00098         if (orig != NULL)
00099         {
00100             DirectFunctionCall1(lo_unlink,
00101                                 ObjectIdGetDatum(atooid(orig)));
00102 
00103             pfree(orig);
00104         }
00105     }
00106 
00107     return PointerGetDatum(rettuple);
00108 }