mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
BEFORE/AFTER ROW INSERT triggers startup from CopyFrom()
RelationBuildTriggers() & FreeTriggerDesc() in trigger.c
This commit is contained in:
parent
c2efeafe9c
commit
8c798538b8
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.27 1997/08/22 14:22:09 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.28 1997/09/01 07:59:04 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -34,6 +34,7 @@
|
|||||||
#include <catalog/catname.h>
|
#include <catalog/catname.h>
|
||||||
#include <catalog/pg_user.h>
|
#include <catalog/pg_user.h>
|
||||||
#include <commands/copy.h>
|
#include <commands/copy.h>
|
||||||
|
#include "commands/trigger.h"
|
||||||
#include <storage/fd.h>
|
#include <storage/fd.h>
|
||||||
|
|
||||||
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
|
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
|
||||||
@ -334,6 +335,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
InsertIndexResult indexRes;
|
InsertIndexResult indexRes;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
Oid loaded_oid;
|
Oid loaded_oid;
|
||||||
|
bool skip_tuple = false;
|
||||||
|
|
||||||
tupDesc = RelationGetTupleDescriptor(rel);
|
tupDesc = RelationGetTupleDescriptor(rel);
|
||||||
attr = tupDesc->attrs;
|
attr = tupDesc->attrs;
|
||||||
@ -603,6 +605,26 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
if (oids)
|
if (oids)
|
||||||
tuple->t_oid = loaded_oid;
|
tuple->t_oid = loaded_oid;
|
||||||
|
|
||||||
|
skip_tuple = false;
|
||||||
|
/* BEFORE ROW INSERT Triggers */
|
||||||
|
if ( rel->trigdesc &&
|
||||||
|
rel->trigdesc->n_before_row[TRIGGER_ACTION_INSERT] > 0 )
|
||||||
|
{
|
||||||
|
HeapTuple newtuple;
|
||||||
|
|
||||||
|
newtuple = ExecBRInsertTriggers (rel, tuple);
|
||||||
|
|
||||||
|
if ( newtuple == NULL ) /* "do nothing" */
|
||||||
|
skip_tuple = true;
|
||||||
|
else if ( newtuple != tuple ) /* modified by Trigger(s) */
|
||||||
|
{
|
||||||
|
pfree (tuple);
|
||||||
|
tuple = newtuple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !skip_tuple )
|
||||||
|
{
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Check the constraints of a tuple
|
* Check the constraints of a tuple
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -623,11 +645,15 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
|
|
||||||
heap_insert(rel, tuple);
|
heap_insert(rel, tuple);
|
||||||
|
|
||||||
if (has_index) {
|
if (has_index)
|
||||||
for (i = 0; i < n_indices; i++) {
|
{
|
||||||
if (indexPred[i] != NULL) {
|
for (i = 0; i < n_indices; i++)
|
||||||
|
{
|
||||||
|
if (indexPred[i] != NULL)
|
||||||
|
{
|
||||||
#ifndef OMIT_PARTIAL_INDEX
|
#ifndef OMIT_PARTIAL_INDEX
|
||||||
/* if tuple doesn't satisfy predicate,
|
/*
|
||||||
|
* if tuple doesn't satisfy predicate,
|
||||||
* don't update index
|
* don't update index
|
||||||
*/
|
*/
|
||||||
slot->val = tuple;
|
slot->val = tuple;
|
||||||
@ -649,6 +675,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
|||||||
if (indexRes) pfree(indexRes);
|
if (indexRes) pfree(indexRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* AFTER ROW INSERT Triggers */
|
||||||
|
if ( rel->trigdesc &&
|
||||||
|
rel->trigdesc->n_after_row[TRIGGER_ACTION_INSERT] > 0 )
|
||||||
|
ExecARInsertTriggers (rel, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
if (binary) pfree(string);
|
if (binary) pfree(string);
|
||||||
|
|
||||||
|
@ -5,13 +5,24 @@
|
|||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
#include <string.h>
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
|
#include "catalog/catname.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
|
#include "catalog/pg_proc.h"
|
||||||
|
#include "catalog/pg_language.h"
|
||||||
#include "catalog/pg_trigger.h"
|
#include "catalog/pg_trigger.h"
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "access/heapam.h"
|
||||||
|
#include "storage/bufmgr.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
void RelationBuildTriggers (Relation relation);
|
||||||
|
void FreeTriggerDesc (Relation relation);
|
||||||
|
|
||||||
void
|
void
|
||||||
CreateTrigger (CreateTrigStmt *stmt)
|
CreateTrigger (CreateTrigStmt *stmt)
|
||||||
{
|
{
|
||||||
@ -25,3 +36,248 @@ DropTrigger (DropTrigStmt *stmt)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RelationBuildTriggers (Relation relation)
|
||||||
|
{
|
||||||
|
TriggerDesc *trigdesc = (TriggerDesc *) palloc (sizeof (TriggerDesc));
|
||||||
|
int ntrigs = relation->rd_rel->reltriggers;
|
||||||
|
Trigger *triggers = NULL;
|
||||||
|
Trigger *build;
|
||||||
|
Relation tgrel;
|
||||||
|
Form_pg_trigger pg_trigger;
|
||||||
|
Relation irel;
|
||||||
|
ScanKeyData skey;
|
||||||
|
HeapTuple tuple;
|
||||||
|
IndexScanDesc sd;
|
||||||
|
RetrieveIndexResult indexRes;
|
||||||
|
Buffer buffer;
|
||||||
|
ItemPointer iptr;
|
||||||
|
struct varlena *val;
|
||||||
|
bool isnull;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
memset (trigdesc, 0, sizeof (TriggerDesc));
|
||||||
|
|
||||||
|
ScanKeyEntryInitialize(&skey,
|
||||||
|
(bits16)0x0,
|
||||||
|
(AttrNumber)1,
|
||||||
|
(RegProcedure)ObjectIdEqualRegProcedure,
|
||||||
|
ObjectIdGetDatum(relation->rd_id));
|
||||||
|
|
||||||
|
tgrel = heap_openr(TriggerRelationName);
|
||||||
|
irel = index_openr(TriggerRelidIndex);
|
||||||
|
sd = index_beginscan(irel, false, 1, &skey);
|
||||||
|
|
||||||
|
for (found = 0; ; )
|
||||||
|
{
|
||||||
|
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||||
|
if (!indexRes)
|
||||||
|
break;
|
||||||
|
|
||||||
|
iptr = &indexRes->heap_iptr;
|
||||||
|
tuple = heap_fetch(tgrel, NowTimeQual, iptr, &buffer);
|
||||||
|
pfree(indexRes);
|
||||||
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
continue;
|
||||||
|
if ( found == ntrigs )
|
||||||
|
elog (WARN, "RelationBuildTriggers: unexpected record found for rel %.*s",
|
||||||
|
NAMEDATALEN, relation->rd_rel->relname.data);
|
||||||
|
|
||||||
|
pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
|
||||||
|
|
||||||
|
if ( triggers == NULL )
|
||||||
|
triggers = (Trigger *) palloc (sizeof (Trigger));
|
||||||
|
else
|
||||||
|
triggers = (Trigger *) repalloc (triggers, (found + 1) * sizeof (Trigger));
|
||||||
|
build = &(triggers[found]);
|
||||||
|
|
||||||
|
build->tgname = nameout (&(pg_trigger->tgname));
|
||||||
|
build->tgfunc = nameout (&(pg_trigger->tgfunc));
|
||||||
|
build->tglang = pg_trigger->tglang;
|
||||||
|
if ( build->tglang != ClanguageId )
|
||||||
|
elog (WARN, "RelationBuildTriggers: unsupported language %u for trigger %s of rel %.*s",
|
||||||
|
build->tglang, build->tgname, NAMEDATALEN, relation->rd_rel->relname.data);
|
||||||
|
build->tgtype = pg_trigger->tgtype;
|
||||||
|
build->tgnargs = pg_trigger->tgnargs;
|
||||||
|
memcpy (build->tgattr, &(pg_trigger->tgattr), 8 * sizeof (int16));
|
||||||
|
val = (struct varlena*) fastgetattr (tuple,
|
||||||
|
Anum_pg_trigger_tgtext,
|
||||||
|
tgrel->rd_att, &isnull);
|
||||||
|
if ( isnull )
|
||||||
|
elog (WARN, "RelationBuildTriggers: tgtext IS NULL for rel %.*s",
|
||||||
|
NAMEDATALEN, relation->rd_rel->relname.data);
|
||||||
|
build->tgtext = byteaout (val);
|
||||||
|
val = (struct varlena*) fastgetattr (tuple,
|
||||||
|
Anum_pg_trigger_tgargs,
|
||||||
|
tgrel->rd_att, &isnull);
|
||||||
|
if ( isnull )
|
||||||
|
elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
|
||||||
|
NAMEDATALEN, relation->rd_rel->relname.data);
|
||||||
|
if ( build->tgnargs > 0 )
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
val = (struct varlena*) fastgetattr (tuple,
|
||||||
|
Anum_pg_trigger_tgargs,
|
||||||
|
tgrel->rd_att, &isnull);
|
||||||
|
if ( isnull )
|
||||||
|
elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
|
||||||
|
NAMEDATALEN, relation->rd_rel->relname.data);
|
||||||
|
p = (char *) VARDATA (val);
|
||||||
|
build->tgargs = (char**) palloc (build->tgnargs * sizeof (char*));
|
||||||
|
for (i = 0; i < build->tgnargs; i++)
|
||||||
|
{
|
||||||
|
build->tgargs[i] = (char*) palloc (strlen (p) + 1);
|
||||||
|
strcpy (build->tgargs[i], p);
|
||||||
|
p += strlen (p) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val = (struct varlena*) fastgetattr (tuple,
|
||||||
|
Anum_pg_trigger_tgwhen,
|
||||||
|
tgrel->rd_att, &isnull);
|
||||||
|
if ( !isnull )
|
||||||
|
build->tgwhen = textout (val);
|
||||||
|
else
|
||||||
|
build->tgwhen = NULL;
|
||||||
|
|
||||||
|
found++;
|
||||||
|
ReleaseBuffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( found < ntrigs )
|
||||||
|
elog (WARN, "RelationBuildTriggers: %d record not found for rel %.*s",
|
||||||
|
ntrigs - found,
|
||||||
|
NAMEDATALEN, relation->rd_rel->relname.data);
|
||||||
|
|
||||||
|
index_endscan (sd);
|
||||||
|
pfree (sd);
|
||||||
|
index_close (irel);
|
||||||
|
heap_close (tgrel);
|
||||||
|
|
||||||
|
/* Build trigdesc */
|
||||||
|
trigdesc->triggers = triggers;
|
||||||
|
for (found = 0; found < ntrigs; found++)
|
||||||
|
{
|
||||||
|
uint16 *n;
|
||||||
|
Trigger ***t, ***tp;
|
||||||
|
|
||||||
|
build = &(triggers[found]);
|
||||||
|
|
||||||
|
if ( TRIGGER_FOR_ROW (build->tgtype) ) /* Is ROW/STATEMENT trigger */
|
||||||
|
{
|
||||||
|
if ( TRIGGER_FOR_BEFORE (build->tgtype) )
|
||||||
|
{
|
||||||
|
n = trigdesc->n_before_row;
|
||||||
|
t = trigdesc->tg_before_row;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = trigdesc->n_after_row;
|
||||||
|
t = trigdesc->tg_after_row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* STATEMENT (NI) */
|
||||||
|
{
|
||||||
|
if ( TRIGGER_FOR_BEFORE (build->tgtype) )
|
||||||
|
{
|
||||||
|
n = trigdesc->n_before_statement;
|
||||||
|
t = trigdesc->tg_before_statement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = trigdesc->n_after_statement;
|
||||||
|
t = trigdesc->tg_after_statement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( TRIGGER_FOR_INSERT (build->tgtype) )
|
||||||
|
{
|
||||||
|
tp = &(t[TRIGGER_ACTION_INSERT]);
|
||||||
|
if ( *tp == NULL )
|
||||||
|
*tp = (Trigger **) palloc (sizeof (Trigger *));
|
||||||
|
else
|
||||||
|
*tp = (Trigger **) repalloc (*tp, (n[TRIGGER_ACTION_INSERT] + 1) *
|
||||||
|
sizeof (Trigger *));
|
||||||
|
(*tp)[n[TRIGGER_ACTION_INSERT]] = build;
|
||||||
|
(n[TRIGGER_ACTION_INSERT])++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( TRIGGER_FOR_DELETE (build->tgtype) )
|
||||||
|
{
|
||||||
|
tp = &(t[TRIGGER_ACTION_DELETE]);
|
||||||
|
if ( *tp == NULL )
|
||||||
|
*tp = (Trigger **) palloc (sizeof (Trigger *));
|
||||||
|
else
|
||||||
|
*tp = (Trigger **) repalloc (*tp, (n[TRIGGER_ACTION_DELETE] + 1) *
|
||||||
|
sizeof (Trigger *));
|
||||||
|
(*tp)[n[TRIGGER_ACTION_DELETE]] = build;
|
||||||
|
(n[TRIGGER_ACTION_DELETE])++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( TRIGGER_FOR_UPDATE (build->tgtype) )
|
||||||
|
{
|
||||||
|
tp = &(t[TRIGGER_ACTION_UPDATE]);
|
||||||
|
if ( *tp == NULL )
|
||||||
|
*tp = (Trigger **) palloc (sizeof (Trigger *));
|
||||||
|
else
|
||||||
|
*tp = (Trigger **) repalloc (*tp, (n[TRIGGER_ACTION_UPDATE] + 1) *
|
||||||
|
sizeof (Trigger *));
|
||||||
|
(*tp)[n[TRIGGER_ACTION_UPDATE]] = build;
|
||||||
|
(n[TRIGGER_ACTION_UPDATE])++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relation->trigdesc = trigdesc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeTriggerDesc (Relation relation)
|
||||||
|
{
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapTuple
|
||||||
|
ExecBRInsertTriggers (Relation rel, HeapTuple tuple)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecARInsertTriggers (Relation rel, HeapTuple tuple)
|
||||||
|
{
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ExecBRDeleteTriggers (Relation rel, ItemPointer tupleid)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecARDeleteTriggers (Relation rel, ItemPointer tupleid)
|
||||||
|
{
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapTuple
|
||||||
|
ExecBRUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecARUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
|
||||||
|
{
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user