diff options
Diffstat (limited to 'contrib/spi/timetravel.c')
-rw-r--r-- | contrib/spi/timetravel.c | 239 |
1 files changed, 122 insertions, 117 deletions
diff --git a/contrib/spi/timetravel.c b/contrib/spi/timetravel.c index aa8d0a47b46..8ffa56edc75 100644 --- a/contrib/spi/timetravel.c +++ b/contrib/spi/timetravel.c @@ -6,11 +6,11 @@ /* Modified by B�JTHE Zolt�n, Hungary, mailto:[email protected] */ #include "executor/spi.h" /* this is what you need to work with SPI */ -#include "commands/trigger.h" /* -"- and triggers */ +#include "commands/trigger.h" /* -"- and triggers */ #include "miscadmin.h" /* for GetPgUserName() */ -#include <ctype.h> /* tolower () */ +#include <ctype.h> /* tolower () */ -#define ABSTIMEOID 702 /* it should be in pg_type.h */ +#define ABSTIMEOID 702 /* it should be in pg_type.h */ /* AbsoluteTime currabstime(void); */ Datum timetravel(PG_FUNCTION_ARGS); @@ -28,13 +28,13 @@ static int nPlans = 0; typedef struct _TTOffList { - struct _TTOffList *next; - char name[1]; -} TTOffList; + struct _TTOffList *next; + char name[1]; +} TTOffList; -static TTOffList TTOff = {NULL,{0}}; +static TTOffList TTOff = {NULL, {0}}; -static int findTTStatus(char *name); +static int findTTStatus(char *name); static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); /* @@ -71,57 +71,57 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); PG_FUNCTION_INFO_V1(timetravel); -Datum /* have to return HeapTuple to Executor */ +Datum /* have to return HeapTuple to Executor */ timetravel(PG_FUNCTION_ARGS) { - TriggerData *trigdata = (TriggerData *) fcinfo->context; - Trigger *trigger; /* to get trigger name */ - int argc; - char **args; /* arguments */ - int attnum[MaxAttrNum]; /* fnumbers of start/stop columns */ + TriggerData *trigdata = (TriggerData *) fcinfo->context; + Trigger *trigger; /* to get trigger name */ + int argc; + char **args; /* arguments */ + int attnum[MaxAttrNum]; /* fnumbers of start/stop columns */ Datum oldtimeon, - oldtimeoff; + oldtimeoff; Datum newtimeon, - newtimeoff, - newuser, - nulltext; - Datum *cvals; /* column values */ - char *cnulls; /* column nulls */ - char *relname; /* triggered relation name */ + newtimeoff, + newuser, + nulltext; + Datum *cvals; /* column values */ + char *cnulls; /* column nulls */ + char *relname; /* triggered relation name */ Relation rel; /* triggered relation */ HeapTuple trigtuple; HeapTuple newtuple = NULL; HeapTuple rettuple; TupleDesc tupdesc; /* tuple description */ - int natts; /* # of attributes */ - EPlan *plan; /* prepared plan */ + int natts; /* # of attributes */ + EPlan *plan; /* prepared plan */ char ident[2 * NAMEDATALEN]; bool isnull; /* to know is some column NULL or not */ bool isinsert = false; - int ret; - int i; + int ret; + int i; /* * Some checks first... */ /* Called by trigger manager ? */ - if(!CALLED_AS_TRIGGER(fcinfo)) + if (!CALLED_AS_TRIGGER(fcinfo)) elog(ERROR, "timetravel: not fired by trigger manager"); /* Should be called for ROW trigger */ - if(TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) + if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) elog(ERROR, "timetravel: can't process STATEMENT events"); /* Should be called BEFORE */ - if(TRIGGER_FIRED_AFTER(trigdata->tg_event)) + if (TRIGGER_FIRED_AFTER(trigdata->tg_event)) elog(ERROR, "timetravel: must be fired before event"); /* INSERT ? */ - if(TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) + if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) isinsert = true; - if(TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) + if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) newtuple = trigdata->tg_newtuple; trigtuple = trigdata->tg_trigtuple; @@ -130,7 +130,7 @@ timetravel(PG_FUNCTION_ARGS) relname = SPI_getrelname(rel); /* check if TT is OFF for this relation */ - if(0==findTTStatus(relname)) + if (0 == findTTStatus(relname)) { /* OFF - nothing to do */ pfree(relname); @@ -140,7 +140,7 @@ timetravel(PG_FUNCTION_ARGS) trigger = trigdata->tg_trigger; argc = trigger->tgnargs; - if(argc != MinAttrNum && argc != MaxAttrNum) + if (argc != MinAttrNum && argc != MaxAttrNum) elog(ERROR, "timetravel (%s): invalid (!= %d or %d) number of arguments %d", relname, MinAttrNum, MaxAttrNum, trigger->tgnargs); @@ -148,39 +148,39 @@ timetravel(PG_FUNCTION_ARGS) tupdesc = rel->rd_att; natts = tupdesc->natts; - for(i = 0 ; i < MinAttrNum ; i++) + for (i = 0; i < MinAttrNum; i++) { attnum[i] = SPI_fnumber(tupdesc, args[i]); - if(attnum[i] < 0) + if (attnum[i] < 0) elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); - if(SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID) + if (SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID) elog(ERROR, "timetravel (%s): attribute %s must be of abstime type", relname, args[i]); } - for( ; i < argc ; i++) + for (; i < argc; i++) { attnum[i] = SPI_fnumber(tupdesc, args[i]); - if(attnum[i] < 0) + if (attnum[i] < 0) elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); - if(SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID) + if (SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID) elog(ERROR, "timetravel (%s): attribute %s must be of text type", relname, args[i]); } /* create fields containing name */ - newuser = DirectFunctionCall1(textin, CStringGetDatum(GetUserNameFromId(GetUserId()))); + newuser = DirectFunctionCall1(textin, CStringGetDatum(GetUserNameFromId(GetUserId()))); - nulltext = (Datum)NULL; + nulltext = (Datum) NULL; - if(isinsert) - { /* INSERT */ - int chnattrs = 0; - int chattrs[MaxAttrNum]; - Datum newvals[MaxAttrNum]; - char newnulls[MaxAttrNum]; + if (isinsert) + { /* INSERT */ + int chnattrs = 0; + int chattrs[MaxAttrNum]; + Datum newvals[MaxAttrNum]; + char newnulls[MaxAttrNum]; oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); - if(isnull) + if (isnull) { newvals[chnattrs] = GetCurrentAbsoluteTime(); newnulls[chnattrs] = ' '; @@ -189,10 +189,10 @@ timetravel(PG_FUNCTION_ARGS) } oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull); - if(isnull) + if (isnull) { - if((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) || - (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME)) + if ((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) || + (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME)) elog(ERROR, "timetravel (%s): %s is infinity", relname, args[a_time_on]); newvals[chnattrs] = NOEND_ABSTIME; newnulls[chnattrs] = ' '; @@ -201,16 +201,16 @@ timetravel(PG_FUNCTION_ARGS) } else { - if((chnattrs == 0 && DatumGetInt32(oldtimeon) > DatumGetInt32(oldtimeoff)) || - (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) > DatumGetInt32(oldtimeoff))) + if ((chnattrs == 0 && DatumGetInt32(oldtimeon) > DatumGetInt32(oldtimeoff)) || + (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) > DatumGetInt32(oldtimeoff))) elog(ERROR, "timetravel (%s): %s gt %s", relname, args[a_time_on], args[a_time_off]); } pfree(relname); - if(chnattrs <= 0) + if (chnattrs <= 0) return PointerGetDatum(trigtuple); - if(argc == MaxAttrNum) + if (argc == MaxAttrNum) { /* clear update_user value */ newvals[chnattrs] = nulltext; @@ -235,33 +235,34 @@ timetravel(PG_FUNCTION_ARGS) /* UPDATE/DELETE: */ oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); - if(isnull) + if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]); oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull); - if(isnull) + if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]); /* * If DELETE/UPDATE of tuple with stop_date neq INFINITY then say * upper Executor to skip operation for this tuple */ - if(newtuple != NULL) - { /* UPDATE */ + if (newtuple != NULL) + { /* UPDATE */ newtimeon = SPI_getbinval(newtuple, tupdesc, attnum[a_time_on], &isnull); - if(isnull) + if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]); newtimeoff = SPI_getbinval(newtuple, tupdesc, attnum[a_time_off], &isnull); - if(isnull) + if (isnull) elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]); - if(oldtimeon != newtimeon || oldtimeoff != newtimeoff) + if (oldtimeon != newtimeon || oldtimeoff != newtimeoff) elog(ERROR, "timetravel (%s): you can't change %s and/or %s columns (use set_timetravel)", relname, args[a_time_on], args[a_time_off]); } - if(oldtimeoff != NOEND_ABSTIME) - { /* current record is a deleted/updated record */ + if (oldtimeoff != NOEND_ABSTIME) + { /* current record is a deleted/updated + * record */ pfree(relname); return PointerGetDatum(NULL); } @@ -269,27 +270,28 @@ timetravel(PG_FUNCTION_ARGS) newtimeoff = GetCurrentAbsoluteTime(); /* Connect to SPI manager */ - if((ret = SPI_connect()) < 0) + if ((ret = SPI_connect()) < 0) elog(ERROR, "timetravel (%s): SPI_connect returned %d", relname, ret); /* Fetch tuple values and nulls */ cvals = (Datum *) palloc(natts * sizeof(Datum)); cnulls = (char *) palloc(natts * sizeof(char)); - for(i = 0; i < natts; i++) + for (i = 0; i < natts; i++) { cvals[i] = SPI_getbinval(trigtuple, tupdesc, i + 1, &isnull); cnulls[i] = (isnull) ? 'n' : ' '; } /* change date column(s) */ - cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current date */ + cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current + * date */ cnulls[attnum[a_time_off] - 1] = ' '; - if(!newtuple) - { /* DELETE */ - if(argc == MaxAttrNum) + if (!newtuple) + { /* DELETE */ + if (argc == MaxAttrNum) { - cvals[attnum[a_del_user] - 1] = newuser; /* set delete user */ + cvals[attnum[a_del_user] - 1] = newuser; /* set delete user */ cnulls[attnum[a_del_user] - 1] = ' '; } } @@ -302,11 +304,11 @@ timetravel(PG_FUNCTION_ARGS) plan = find_plan(ident, &Plans, &nPlans); /* if there is no plan ... */ - if(plan->splan == NULL) + if (plan->splan == NULL) { - void *pplan; - Oid *ctypes; - char sql[8192]; + void *pplan; + Oid *ctypes; + char sql[8192]; /* allocate ctypes for preparation */ ctypes = (Oid *) palloc(natts * sizeof(Oid)); @@ -315,15 +317,15 @@ timetravel(PG_FUNCTION_ARGS) * Construct query: INSERT INTO _relation_ VALUES ($1, ...) */ snprintf(sql, sizeof(sql), "INSERT INTO %s VALUES (", relname); - for(i = 1; i <= natts; i++) + for (i = 1; i <= natts; i++) { ctypes[i - 1] = SPI_gettypeid(tupdesc, i); - if(!(tupdesc->attrs[i - 1]->attisdropped)) /* skip dropped columns */ - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d%s", - i, (i < natts) ? ", " : ")" ); + if (!(tupdesc->attrs[i - 1]->attisdropped)) /* skip dropped columns */ + snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d%s", + i, (i < natts) ? ", " : ")"); #if 0 - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d /* %d */ %s", - i, ctypes[i-1], (i < natts) ? ", " : ")" ); + snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d /* %d */ %s", + i, ctypes[i - 1], (i < natts) ? ", " : ")"); #endif } @@ -331,7 +333,7 @@ timetravel(PG_FUNCTION_ARGS) /* Prepare plan for query */ pplan = SPI_prepare(sql, natts, ctypes); - if(pplan == NULL) + if (pplan == NULL) elog(ERROR, "timetravel (%s): SPI_prepare returned %d", relname, SPI_result); /* @@ -340,7 +342,7 @@ timetravel(PG_FUNCTION_ARGS) * use. */ pplan = SPI_saveplan(pplan); - if(pplan == NULL) + if (pplan == NULL) elog(ERROR, "timetravel (%s): SPI_saveplan returned %d", relname, SPI_result); plan->splan = pplan; @@ -351,14 +353,14 @@ timetravel(PG_FUNCTION_ARGS) */ ret = SPI_execp(plan->splan, cvals, cnulls, 0); - if(ret < 0) + if (ret < 0) elog(ERROR, "timetravel (%s): SPI_execp returned %d", relname, ret); /* Tuple to return to upper Executor ... */ - if(newtuple) - { /* UPDATE */ - int chnattrs = 0; - int chattrs[MaxAttrNum]; + if (newtuple) + { /* UPDATE */ + int chnattrs = 0; + int chattrs[MaxAttrNum]; Datum newvals[MaxAttrNum]; char newnulls[MaxAttrNum]; @@ -372,7 +374,7 @@ timetravel(PG_FUNCTION_ARGS) chattrs[chnattrs] = attnum[a_time_off]; chnattrs++; - if(argc == MaxAttrNum) + if (argc == MaxAttrNum) { /* set update_user value */ newvals[chnattrs] = newuser; @@ -399,7 +401,8 @@ timetravel(PG_FUNCTION_ARGS) */ /* SPI_pfree(tmptuple); */ } - else /* DELETE case */ + else +/* DELETE case */ rettuple = trigtuple; SPI_finish(); /* don't forget say Bye to SPI mgr */ @@ -417,23 +420,24 @@ PG_FUNCTION_INFO_V1(set_timetravel); Datum set_timetravel(PG_FUNCTION_ARGS) { - Name relname = PG_GETARG_NAME(0); - int32 on = PG_GETARG_INT32(1); - char *rname; - char *d; - char *s; + Name relname = PG_GETARG_NAME(0); + int32 on = PG_GETARG_INT32(1); + char *rname; + char *d; + char *s; int32 ret; - TTOffList *p,*pp; + TTOffList *p, + *pp; - for(pp = (p = &TTOff)->next; pp; pp=(p=pp)->next) + for (pp = (p = &TTOff)->next; pp; pp = (p = pp)->next) { - if(namestrcmp(relname, pp->name) == 0) + if (namestrcmp(relname, pp->name) == 0) break; } - if(pp) + if (pp) { /* OFF currently */ - if(on != 0) + if (on != 0) { /* turn ON */ p->next = pp->next; @@ -444,20 +448,20 @@ set_timetravel(PG_FUNCTION_ARGS) else { /* ON currently */ - if(on == 0) + if (on == 0) { /* turn OFF */ s = rname = DatumGetCString(DirectFunctionCall1(nameout, NameGetDatum(relname))); - if(s) + if (s) { - pp = malloc(sizeof(TTOffList)+strlen(rname)); - if(pp) + pp = malloc(sizeof(TTOffList) + strlen(rname)); + if (pp) { pp->next = NULL; p->next = pp; d = pp->name; while (*s) - *d++ = tolower((unsigned char)*s++); + *d++ = tolower((unsigned char) *s++); *d = '\0'; } pfree(rname); @@ -470,7 +474,7 @@ set_timetravel(PG_FUNCTION_ARGS) /* * get_timetravel (relname) -- - * get timetravel status for specified relation (ON/OFF) + * get timetravel status for specified relation (ON/OFF) */ PG_FUNCTION_INFO_V1(get_timetravel); @@ -478,11 +482,11 @@ Datum get_timetravel(PG_FUNCTION_ARGS) { Name relname = PG_GETARG_NAME(0); - TTOffList *pp; + TTOffList *pp; - for(pp = TTOff.next; pp; pp = pp->next) + for (pp = TTOff.next; pp; pp = pp->next) { - if(namestrcmp(relname, pp->name) == 0) + if (namestrcmp(relname, pp->name) == 0) PG_RETURN_INT32(0); } PG_RETURN_INT32(1); @@ -491,9 +495,10 @@ get_timetravel(PG_FUNCTION_ARGS) static int findTTStatus(char *name) { - TTOffList* pp; - for(pp = TTOff.next; pp; pp = pp->next) - if(strcasecmp(name, pp->name) == 0) + TTOffList *pp; + + for (pp = TTOff.next; pp; pp = pp->next) + if (strcasecmp(name, pp->name) == 0) return 0; return 1; } @@ -509,17 +514,17 @@ currabstime() static EPlan * find_plan(char *ident, EPlan ** eplan, int *nplans) { - EPlan *newp; - int i; + EPlan *newp; + int i; - if(*nplans > 0) + if (*nplans > 0) { - for(i = 0; i < *nplans; i++) + for (i = 0; i < *nplans; i++) { - if(strcmp((*eplan)[i].ident, ident) == 0) + if (strcmp((*eplan)[i].ident, ident) == 0) break; } - if(i != *nplans) + if (i != *nplans) return (*eplan + i); *eplan = (EPlan *) realloc(*eplan, (i + 1) * sizeof(EPlan)); newp = *eplan + i; |