LCOV - differential code coverage report
Current view: top level - contrib/spi - autoinc.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 87.7 % 57 50 7 50
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 3 3 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * contrib/spi/autoinc.c
       3                 :  */
       4                 : #include "postgres.h"
       5                 : 
       6                 : #include "access/htup_details.h"
       7                 : #include "catalog/pg_type.h"
       8                 : #include "commands/sequence.h"
       9                 : #include "commands/trigger.h"
      10                 : #include "executor/spi.h"
      11                 : #include "utils/builtins.h"
      12                 : #include "utils/rel.h"
      13                 : 
      14 CBC           6 : PG_MODULE_MAGIC;
      15                 : 
      16               7 : PG_FUNCTION_INFO_V1(autoinc);
      17                 : 
      18                 : Datum
      19              36 : autoinc(PG_FUNCTION_ARGS)
      20                 : {
      21              36 :     TriggerData *trigdata = (TriggerData *) fcinfo->context;
      22                 :     Trigger    *trigger;        /* to get trigger name */
      23                 :     int         nargs;          /* # of arguments */
      24                 :     int        *chattrs;        /* attnums of attributes to change */
      25              36 :     int         chnattrs = 0;   /* # of above */
      26                 :     Datum      *newvals;        /* vals of above */
      27                 :     bool       *newnulls;       /* null flags for above */
      28                 :     char      **args;           /* arguments */
      29                 :     char       *relname;        /* triggered relation name */
      30                 :     Relation    rel;            /* triggered relation */
      31              36 :     HeapTuple   rettuple = NULL;
      32                 :     TupleDesc   tupdesc;        /* tuple description */
      33                 :     bool        isnull;
      34                 :     int         i;
      35                 : 
      36              36 :     if (!CALLED_AS_TRIGGER(fcinfo))
      37                 :         /* internal error */
      38 UBC           0 :         elog(ERROR, "not fired by trigger manager");
      39 CBC          36 :     if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
      40                 :         /* internal error */
      41 UBC           0 :         elog(ERROR, "must be fired for row");
      42 CBC          36 :     if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
      43                 :         /* internal error */
      44 UBC           0 :         elog(ERROR, "must be fired before event");
      45                 : 
      46 CBC          36 :     if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
      47              18 :         rettuple = trigdata->tg_trigtuple;
      48              18 :     else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
      49              18 :         rettuple = trigdata->tg_newtuple;
      50                 :     else
      51                 :         /* internal error */
      52 UBC           0 :         elog(ERROR, "cannot process DELETE events");
      53                 : 
      54 CBC          36 :     rel = trigdata->tg_relation;
      55              36 :     relname = SPI_getrelname(rel);
      56                 : 
      57              36 :     trigger = trigdata->tg_trigger;
      58                 : 
      59              36 :     nargs = trigger->tgnargs;
      60              36 :     if (nargs <= 0 || nargs % 2 != 0)
      61                 :         /* internal error */
      62 UBC           0 :         elog(ERROR, "autoinc (%s): even number gt 0 of arguments was expected", relname);
      63                 : 
      64 CBC          36 :     args = trigger->tgargs;
      65              36 :     tupdesc = rel->rd_att;
      66                 : 
      67              36 :     chattrs = (int *) palloc(nargs / 2 * sizeof(int));
      68              36 :     newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
      69              36 :     newnulls = (bool *) palloc(nargs / 2 * sizeof(bool));
      70                 : 
      71              72 :     for (i = 0; i < nargs;)
      72                 :     {
      73              36 :         int         attnum = SPI_fnumber(tupdesc, args[i]);
      74                 :         int32       val;
      75                 :         Datum       seqname;
      76                 : 
      77              36 :         if (attnum <= 0)
      78 UBC           0 :             ereport(ERROR,
      79                 :                     (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
      80                 :                      errmsg("\"%s\" has no attribute \"%s\"",
      81                 :                             relname, args[i])));
      82                 : 
      83 CBC          36 :         if (SPI_gettypeid(tupdesc, attnum) != INT4OID)
      84 UBC           0 :             ereport(ERROR,
      85                 :                     (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
      86                 :                      errmsg("attribute \"%s\" of \"%s\" must be type INT4",
      87                 :                             args[i], relname)));
      88                 : 
      89 CBC          36 :         val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull));
      90                 : 
      91              36 :         if (!isnull && val != 0)
      92                 :         {
      93              27 :             i += 2;
      94              27 :             continue;
      95                 :         }
      96                 : 
      97               9 :         i++;
      98               9 :         chattrs[chnattrs] = attnum;
      99               9 :         seqname = CStringGetTextDatum(args[i]);
     100               9 :         newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
     101                 :         /* nextval now returns int64; coerce down to int32 */
     102               9 :         newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
     103               9 :         if (DatumGetInt32(newvals[chnattrs]) == 0)
     104                 :         {
     105               3 :             newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
     106               3 :             newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
     107                 :         }
     108               9 :         newnulls[chnattrs] = false;
     109               9 :         pfree(DatumGetTextPP(seqname));
     110               9 :         chnattrs++;
     111               9 :         i++;
     112                 :     }
     113                 : 
     114              36 :     if (chnattrs > 0)
     115                 :     {
     116               9 :         rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc,
     117                 :                                              chnattrs, chattrs,
     118                 :                                              newvals, newnulls);
     119                 :     }
     120                 : 
     121              36 :     pfree(relname);
     122              36 :     pfree(chattrs);
     123              36 :     pfree(newvals);
     124              36 :     pfree(newnulls);
     125                 : 
     126              36 :     return PointerGetDatum(rettuple);
     127                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a