1 /* 2 * PostgreSQL definitions for managed Large Objects. 3 * 4 * contrib/lo/lo.c 5 * 6 */ 7 8 #include "postgres.h" 9 10 #include "commands/trigger.h" 11 #include "executor/spi.h" 12 #include "utils/builtins.h" 13 #include "utils/rel.h" 14 15 PG_MODULE_MAGIC; 16 17 18 /* 19 * This is the trigger that protects us from orphaned large objects 20 */ 21 PG_FUNCTION_INFO_V1(lo_manage); 22 23 Datum 24 lo_manage(PG_FUNCTION_ARGS) 25 { 26 TriggerData *trigdata = (TriggerData *) fcinfo->context; 27 int attnum; /* attribute number to monitor */ 28 char **args; /* Args containing attr name */ 29 TupleDesc tupdesc; /* Tuple Descriptor */ 30 HeapTuple rettuple; /* Tuple to be returned */ 31 bool isdelete; /* are we deleting? */ 32 HeapTuple newtuple; /* The new value for tuple */ 33 HeapTuple trigtuple; /* The original value of tuple */ 34 35 if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */ 36 elog(ERROR, "lo_manage: not fired by trigger manager"); 37 38 if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) /* internal error */ 39 elog(ERROR, "%s: must be fired for row", 40 trigdata->tg_trigger->tgname); 41 42 /* 43 * Fetch some values from trigdata 44 */ 45 newtuple = trigdata->tg_newtuple; 46 trigtuple = trigdata->tg_trigtuple; 47 tupdesc = trigdata->tg_relation->rd_att; 48 args = trigdata->tg_trigger->tgargs; 49 50 if (args == NULL) /* internal error */ 51 elog(ERROR, "%s: no column name provided in the trigger definition", 52 trigdata->tg_trigger->tgname); 53 54 /* tuple to return to Executor */ 55 if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) 56 rettuple = newtuple; 57 else 58 rettuple = trigtuple; 59 60 /* Are we deleting the row? */ 61 isdelete = TRIGGER_FIRED_BY_DELETE(trigdata->tg_event); 62 63 /* Get the column we're interested in */ 64 attnum = SPI_fnumber(tupdesc, args[0]); 65 66 if (attnum <= 0) 67 elog(ERROR, "%s: column \"%s\" does not exist", 68 trigdata->tg_trigger->tgname, args[0]); 69 70 /* 71 * Handle updates 72 * 73 * Here, if the value of the monitored attribute changes, then the large 74 * object associated with the original value is unlinked. 75 */ 76 if (newtuple != NULL && 77 bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber, trigdata->tg_updatedcols)) 78 { 79 char *orig = SPI_getvalue(trigtuple, tupdesc, attnum); 80 char *newv = SPI_getvalue(newtuple, tupdesc, attnum); 81 82 if (orig != NULL && (newv == NULL || strcmp(orig, newv) != 0)) 83 DirectFunctionCall1(be_lo_unlink, 84 ObjectIdGetDatum(atooid(orig))); 85 86 if (newv) 87 pfree(newv); 88 if (orig) 89 pfree(orig); 90 } 91 92 /* 93 * Handle deleting of rows 94 * 95 * Here, we unlink the large object associated with the managed attribute 96 */ 97 if (isdelete) 98 { 99 char *orig = SPI_getvalue(trigtuple, tupdesc, attnum); 100 101 if (orig != NULL) 102 { 103 DirectFunctionCall1(be_lo_unlink, 104 ObjectIdGetDatum(atooid(orig))); 105 106 pfree(orig); 107 } 108 } 109 110 return PointerGetDatum(rettuple); 111 } 112