Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  plsample.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * plsample.c
 *   Handler for the PL/Sample procedural language
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *  src/test/modules/plsample/plsample.c
 *
 *-------------------------------------------------------------------------
 */


#include "postgres.h"

#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "utils/fmgrprotos.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(plsample_call_handler);

static Datum plsample_func_handler(PG_FUNCTION_ARGS);
static HeapTuple plsample_trigger_handler(PG_FUNCTION_ARGS);

/*
 * Handle function, procedure, and trigger calls.
 */

Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
 Datum  retval = (Datum) 0;

 /*
  * Many languages will require cleanup that happens even in the event of
  * an error.  That can happen in the PG_FINALLY block.  If none is needed,
  * this PG_TRY construct can be omitted.
 */

 PG_TRY();
 {
  /*
   * Determine if called as function or trigger and call appropriate
   * subhandler.
 */

  if (CALLED_AS_TRIGGER(fcinfo))
  {
   /*
    * This function has been called as a trigger function, where
    * (TriggerData *) fcinfo->context includes the information of the
    * context.
 */

   retval = PointerGetDatum(plsample_trigger_handler(fcinfo));
  }
  else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
  {
   /*
    * This function is called as an event trigger function, where
    * (EventTriggerData *) fcinfo->context includes the information
    * of the context.
    *
    * TODO: provide an example handler.
 */

  }
  else
  {
   /* Regular function handler */
   retval = plsample_func_handler(fcinfo);
  }
 }
 PG_FINALLY();
 {
 }
 PG_END_TRY();

 return retval;
}

/*
 * plsample_func_handler
 *
 * Function called by the call handler for function execution.
 */

static Datum
plsample_func_handler(PG_FUNCTION_ARGS)
{
 HeapTuple pl_tuple;
 Datum  ret;
 char    *source;
 bool  isnull;
 FmgrInfo   *arg_out_func;
 Form_pg_type type_struct;
 HeapTuple type_tuple;
 Form_pg_proc pl_struct;
 volatile MemoryContext proc_cxt = NULL;
 Oid     *argtypes;
 char   **argnames;
 char    *argmodes;
 char    *proname;
 Form_pg_type pg_type_entry;
 Oid   result_typioparam;
 Oid   prorettype;
 FmgrInfo result_in_func;
 int   numargs;

 /* Fetch the function's pg_proc entry. */
 pl_tuple = SearchSysCache1(PROCOID,
          ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
 if (!HeapTupleIsValid(pl_tuple))
  elog(ERROR, "cache lookup failed for function %u",
    fcinfo->flinfo->fn_oid);

 /*
  * Extract and print the source text of the function.  This can be used as
  * a base for the function validation and execution.
 */

 pl_struct = (Form_pg_proc) GETSTRUCT(pl_tuple);
 proname = pstrdup(NameStr(pl_struct->proname));
 ret = SysCacheGetAttr(PROCOID, pl_tuple, Anum_pg_proc_prosrc, &isnull);
 if (isnull)
  elog(ERROR, "could not find source text of function \"%s\"",
    proname);
 source = DatumGetCString(DirectFunctionCall1(textout, ret));
 ereport(NOTICE,
   (errmsg("source text of function \"%s\": %s",
     proname, source)));

 /*
  * Allocate a context that will hold all the Postgres data for the
  * procedure.
 */

 proc_cxt = AllocSetContextCreate(TopMemoryContext,
          "PL/Sample function",
          ALLOCSET_SMALL_SIZES);

 arg_out_func = (FmgrInfo *) palloc0(fcinfo->nargs * sizeof(FmgrInfo));
 numargs = get_func_arg_info(pl_tuple, &argtypes, &argnames, &argmodes);

 /*
  * Iterate through all of the function arguments, printing each input
  * value.
 */

 for (int i = 0; i < numargs; i++)
 {
  Oid   argtype = pl_struct->proargtypes.values[i];
  char    *value;

  type_tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(argtype));
  if (!HeapTupleIsValid(type_tuple))
   elog(ERROR, "cache lookup failed for type %u", argtype);

  type_struct = (Form_pg_type) GETSTRUCT(type_tuple);
  fmgr_info_cxt(type_struct->typoutput, &(arg_out_func[i]), proc_cxt);
  ReleaseSysCache(type_tuple);

  value = OutputFunctionCall(&arg_out_func[i], fcinfo->args[i].value);
  ereport(NOTICE,
    (errmsg("argument: %d; name: %s; value: %s",
      i, argnames[i], value)));
 }

 /* Type of the result */
 prorettype = pl_struct->prorettype;
 ReleaseSysCache(pl_tuple);

 /*
  * Get the required information for input conversion of the return value.
  *
  * If the function uses VOID as result, it is better to return NULL.
  * Anyway, let's be honest.  This is just a template, so there is not much
  * we can do here.  This returns NULL except if the result type is text,
  * where the result is the source text of the function.
 */

 if (prorettype != TEXTOID)
  PG_RETURN_NULL();

 type_tuple = SearchSysCache1(TYPEOID,
         ObjectIdGetDatum(prorettype));
 if (!HeapTupleIsValid(type_tuple))
  elog(ERROR, "cache lookup failed for type %u", prorettype);
 pg_type_entry = (Form_pg_type) GETSTRUCT(type_tuple);
 result_typioparam = getTypeIOParam(type_tuple);

 fmgr_info_cxt(pg_type_entry->typinput, &result_in_func, proc_cxt);
 ReleaseSysCache(type_tuple);

 ret = InputFunctionCall(&result_in_func, source, result_typioparam, -1);
 PG_RETURN_DATUM(ret);
}

/*
 * plsample_trigger_handler
 *
 * Function called by the call handler for trigger execution.
 */

static HeapTuple
plsample_trigger_handler(PG_FUNCTION_ARGS)
{
 TriggerData *trigdata = (TriggerData *) fcinfo->context;
 char    *string;
 volatile HeapTuple rettup;
 HeapTuple pl_tuple;
 Datum  ret;
 char    *source;
 bool  isnull;
 Form_pg_proc pl_struct;
 char    *proname;
 int   rc PG_USED_FOR_ASSERTS_ONLY;

 /* Make sure this is being called from a trigger. */
 if (!CALLED_AS_TRIGGER(fcinfo))
  elog(ERROR, "not called by trigger manager");

 /* Connect to the SPI manager */
 SPI_connect();

 rc = SPI_register_trigger_data(trigdata);
 Assert(rc >= 0);

 /* Fetch the function's pg_proc entry. */
 pl_tuple = SearchSysCache1(PROCOID,
          ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
 if (!HeapTupleIsValid(pl_tuple))
  elog(ERROR, "cache lookup failed for function %u",
    fcinfo->flinfo->fn_oid);

 /*
  * Code Retrieval
  *
  * Extract and print the source text of the function.  This can be used as
  * a base for the function validation and execution.
 */

 pl_struct = (Form_pg_proc) GETSTRUCT(pl_tuple);
 proname = pstrdup(NameStr(pl_struct->proname));
 ret = SysCacheGetAttr(PROCOID, pl_tuple, Anum_pg_proc_prosrc, &isnull);
 if (isnull)
  elog(ERROR, "could not find source text of function \"%s\"",
    proname);
 source = DatumGetCString(DirectFunctionCall1(textout, ret));
 ereport(NOTICE,
   (errmsg("source text of function \"%s\": %s",
     proname, source)));

 /*
  * We're done with the pg_proc tuple, so release it.  (Note that the
  * "proname" and "source" strings are now standalone copies.)
 */

 ReleaseSysCache(pl_tuple);

 /*
  * Code Augmentation
  *
  * The source text may be augmented here, such as by wrapping it as the
  * body of a function in the target language, prefixing a parameter list
  * with names like TD_name, TD_relid, TD_table_name, TD_table_schema,
  * TD_event, TD_when, TD_level, TD_NEW, TD_OLD, and args, using whatever
  * types in the target language are convenient. The augmented text can be
  * cached in a longer-lived memory context, or, if the target language
  * uses a compilation step, that can be done here, caching the result of
  * the compilation.
 */


 /*
  * Code Execution
  *
  * Here the function (the possibly-augmented source text, or the result of
  * compilation if the target language uses such a step) should be
  * executed, after binding values from the TriggerData struct to the
  * appropriate parameters.
  *
  * In this example we just print a lot of info via ereport.
 */


 PG_TRY();
 {
  ereport(NOTICE,
    (errmsg("trigger name: %s", trigdata->tg_trigger->tgname)));
  string = SPI_getrelname(trigdata->tg_relation);
  ereport(NOTICE, (errmsg("trigger relation: %s", string)));

  string = SPI_getnspname(trigdata->tg_relation);
  ereport(NOTICE, (errmsg("trigger relation schema: %s", string)));

  /* Example handling of different trigger aspects. */

  if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
  {
   ereport(NOTICE, (errmsg("triggered by INSERT")));
   rettup = trigdata->tg_trigtuple;
  }
  else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
  {
   ereport(NOTICE, (errmsg("triggered by DELETE")));
   rettup = trigdata->tg_trigtuple;
  }
  else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
  {
   ereport(NOTICE, (errmsg("triggered by UPDATE")));
   rettup = trigdata->tg_trigtuple;
  }
  else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
  {
   ereport(NOTICE, (errmsg("triggered by TRUNCATE")));
   rettup = trigdata->tg_trigtuple;
  }
  else
   elog(ERROR, "unrecognized event: %u", trigdata->tg_event);

  if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
   ereport(NOTICE, (errmsg("triggered BEFORE")));
  else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
   ereport(NOTICE, (errmsg("triggered AFTER")));
  else if (TRIGGER_FIRED_INSTEAD(trigdata->tg_event))
   ereport(NOTICE, (errmsg("triggered INSTEAD OF")));
  else
   elog(ERROR, "unrecognized when: %u", trigdata->tg_event);

  if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
   ereport(NOTICE, (errmsg("triggered per row")));
  else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
   ereport(NOTICE, (errmsg("triggered per statement")));
  else
   elog(ERROR, "unrecognized level: %u", trigdata->tg_event);

  /*
   * Iterate through all of the trigger arguments, printing each input
   * value.
 */

  for (int i = 0; i < trigdata->tg_trigger->tgnargs; i++)
   ereport(NOTICE,
     (errmsg("trigger arg[%i]: %s", i,
       trigdata->tg_trigger->tgargs[i])));
 }
 PG_CATCH();
 {
  /* Error cleanup code would go here */
  PG_RE_THROW();
 }
 PG_END_TRY();

 if (SPI_finish() != SPI_OK_FINISH)
  elog(ERROR, "SPI_finish() failed");

 return rettup;
}

Messung V0.5 in Prozent
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002