Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
7c50767f
Commit
7c50767f
authored
Nov 16, 2001
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove 'triggered data change violation' error check, per recent
discussions in pghackers.
parent
306798de
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
119 additions
and
229 deletions
+119
-229
src/backend/commands/trigger.c
src/backend/commands/trigger.c
+118
-225
src/include/commands/trigger.h
src/include/commands/trigger.h
+1
-4
No files found.
src/backend/commands/trigger.c
View file @
7c50767f
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.9
8 2001/11/12 00:00:55
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.9
9 2001/11/16 16:31:16
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -935,10 +935,7 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
...
@@ -935,10 +935,7 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
{
{
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
/* Must save info if there are any deferred triggers on this rel */
if
(
trigdesc
->
n_after_row
[
TRIGGER_EVENT_INSERT
]
>
0
)
if
(
trigdesc
->
n_after_row
[
TRIGGER_EVENT_INSERT
]
>
0
||
trigdesc
->
n_after_row
[
TRIGGER_EVENT_UPDATE
]
>
0
||
trigdesc
->
n_after_row
[
TRIGGER_EVENT_DELETE
]
>
0
)
DeferredTriggerSaveEvent
(
relinfo
,
TRIGGER_EVENT_INSERT
,
DeferredTriggerSaveEvent
(
relinfo
,
TRIGGER_EVENT_INSERT
,
NULL
,
trigtuple
);
NULL
,
trigtuple
);
}
}
...
@@ -1000,9 +997,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
...
@@ -1000,9 +997,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
{
{
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
/* Must save info if there are upd/del deferred triggers on this rel */
if
(
trigdesc
->
n_after_row
[
TRIGGER_EVENT_DELETE
]
>
0
)
if
(
trigdesc
->
n_after_row
[
TRIGGER_EVENT_UPDATE
]
>
0
||
trigdesc
->
n_after_row
[
TRIGGER_EVENT_DELETE
]
>
0
)
{
{
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
relinfo
,
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
relinfo
,
tupleid
,
NULL
);
tupleid
,
NULL
);
...
@@ -1077,9 +1072,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
...
@@ -1077,9 +1072,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
{
{
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
/* Must save info if there are upd/del deferred triggers on this rel */
if
(
trigdesc
->
n_after_row
[
TRIGGER_EVENT_UPDATE
]
>
0
)
if
(
trigdesc
->
n_after_row
[
TRIGGER_EVENT_UPDATE
]
>
0
||
trigdesc
->
n_after_row
[
TRIGGER_EVENT_DELETE
]
>
0
)
{
{
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
relinfo
,
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
relinfo
,
tupleid
,
NULL
);
tupleid
,
NULL
);
...
@@ -1208,17 +1201,17 @@ static bool deftrig_all_isdeferred;
...
@@ -1208,17 +1201,17 @@ static bool deftrig_all_isdeferred;
static
List
*
deftrig_trigstates
;
static
List
*
deftrig_trigstates
;
/* ----------
/* ----------
* The list of events during the entire transaction. deftrig_events
* The list of pending deferred trigger events during the current transaction.
* is the head, deftrig_event_tail is the last entry. Because this can
*
* grow pretty large, we don't use separate List nodes, but instead thread
* deftrig_events is the head, deftrig_event_tail is the last entry.
* the list through the dte_next fields of the member nodes. Saves just a
* Because this can grow pretty large, we don't use separate List nodes,
* few bytes per entry, but that adds up.
* but instead thread the list through the dte_next fields of the member
* nodes. Saves just a few bytes per entry, but that adds up.
*
*
* XXX Need to be able to shove this data out to a file if it grows too
* XXX Need to be able to shove this data out to a file if it grows too
* large...
* large...
* ----------
* ----------
*/
*/
static
int
deftrig_n_events
;
static
DeferredTriggerEvent
deftrig_events
;
static
DeferredTriggerEvent
deftrig_events
;
static
DeferredTriggerEvent
deftrig_event_tail
;
static
DeferredTriggerEvent
deftrig_event_tail
;
...
@@ -1284,7 +1277,6 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
...
@@ -1284,7 +1277,6 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
* deferredTriggerAddEvent()
* deferredTriggerAddEvent()
*
*
* Add a new trigger event to the queue.
* Add a new trigger event to the queue.
* Caller must have switched into appropriate memory context!
* ----------
* ----------
*/
*/
static
void
static
void
...
@@ -1307,44 +1299,6 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
...
@@ -1307,44 +1299,6 @@ deferredTriggerAddEvent(DeferredTriggerEvent event)
deftrig_event_tail
->
dte_next
=
event
;
deftrig_event_tail
->
dte_next
=
event
;
deftrig_event_tail
=
event
;
deftrig_event_tail
=
event
;
}
}
deftrig_n_events
++
;
}
/* ----------
* deferredTriggerGetPreviousEvent()
*
* Scan the eventlist to find the event a given OLD tuple
* resulted from in the same transaction.
* ----------
*/
static
DeferredTriggerEvent
deferredTriggerGetPreviousEvent
(
Oid
relid
,
ItemPointer
ctid
)
{
DeferredTriggerEvent
previous
=
NULL
;
DeferredTriggerEvent
prev
;
/* Search the list to find the last event affecting this tuple */
for
(
prev
=
deftrig_events
;
prev
!=
NULL
;
prev
=
prev
->
dte_next
)
{
if
(
prev
->
dte_relid
!=
relid
)
continue
;
if
(
prev
->
dte_event
&
TRIGGER_DEFERRED_CANCELED
)
continue
;
if
(
ItemPointerGetBlockNumber
(
ctid
)
==
ItemPointerGetBlockNumber
(
&
(
prev
->
dte_newctid
))
&&
ItemPointerGetOffsetNumber
(
ctid
)
==
ItemPointerGetOffsetNumber
(
&
(
prev
->
dte_newctid
)))
previous
=
prev
;
}
if
(
previous
==
NULL
)
elog
(
ERROR
,
"deferredTriggerGetPreviousEvent: event for tuple %s not found"
,
DatumGetCString
(
DirectFunctionCall1
(
tidout
,
PointerGetDatum
(
ctid
))));
return
previous
;
}
}
...
@@ -1473,18 +1427,25 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
...
@@ -1473,18 +1427,25 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
static
void
static
void
deferredTriggerInvokeEvents
(
bool
immediate_only
)
deferredTriggerInvokeEvents
(
bool
immediate_only
)
{
{
DeferredTriggerEvent
event
;
DeferredTriggerEvent
event
,
prev_event
=
NULL
;
MemoryContext
per_tuple_context
;
MemoryContext
per_tuple_context
;
Relation
rel
=
NULL
;
Relation
rel
=
NULL
;
FmgrInfo
*
finfo
=
NULL
;
FmgrInfo
*
finfo
=
NULL
;
/*
/*
* For now we process all events - to speedup transaction blocks we
* If immediate_only is true, we remove fully-processed events from
* need to remember the actual end of the queue at EndQuery and
* the event queue to recycle space. If immediate_only is false,
* process only events that are newer. On state changes we simply
* we are going to discard the whole event queue on return anyway,
* reset the position to the beginning of the queue and process all
* so no need to bother with "retail" pfree's.
* events once with the new states when the SET CONSTRAINTS ...
*
* command finishes and calls EndQuery.
* In a scenario with many commands in a transaction and many
* deferred-to-end-of-transaction triggers, it could get annoying
* to rescan all the deferred triggers at each command end.
* To speed this up, we could remember the actual end of the queue at
* EndQuery and examine only events that are newer. On state changes
* we simply reset the saved position to the beginning of the queue
* and process all events once with the new states.
*/
*/
/* Make a per-tuple memory context for trigger function calls */
/* Make a per-tuple memory context for trigger function calls */
...
@@ -1495,80 +1456,118 @@ deferredTriggerInvokeEvents(bool immediate_only)
...
@@ -1495,80 +1456,118 @@ deferredTriggerInvokeEvents(bool immediate_only)
ALLOCSET_DEFAULT_INITSIZE
,
ALLOCSET_DEFAULT_INITSIZE
,
ALLOCSET_DEFAULT_MAXSIZE
);
ALLOCSET_DEFAULT_MAXSIZE
);
for
(
event
=
deftrig_events
;
event
!=
NULL
;
event
=
event
->
dte_next
)
event
=
deftrig_events
;
while
(
event
!=
NULL
)
{
{
bool
still_deferred_ones
;
bool
still_deferred_ones
=
false
;
DeferredTriggerEvent
next_event
;
int
i
;
int
i
;
/*
/*
* Check if event is completely done.
* Check if event is already completely done.
*/
if
(
event
->
dte_event
&
(
TRIGGER_DEFERRED_DONE
|
TRIGGER_DEFERRED_CANCELED
))
continue
;
MemoryContextReset
(
per_tuple_context
);
/*
* Check each trigger item in the event.
*/
*/
still_deferred_ones
=
false
;
if
(
!
(
event
->
dte_event
&
(
TRIGGER_DEFERRED_DONE
|
for
(
i
=
0
;
i
<
event
->
dte_n_items
;
i
++
)
TRIGGER_DEFERRED_CANCELED
))
)
{
{
if
(
event
->
dte_item
[
i
].
dti_state
&
TRIGGER_DEFERRED_DONE
)
MemoryContextReset
(
per_tuple_context
);
continue
;
/*
* This trigger item hasn't been called yet. Check if we
* should call it now.
*/
if
(
immediate_only
&&
deferredTriggerCheckState
(
event
->
dte_item
[
i
].
dti_tgoid
,
event
->
dte_item
[
i
].
dti_state
))
{
still_deferred_ones
=
true
;
continue
;
}
/*
/*
* So let's fire it... but first, open the correct relation if
* Check each trigger item in the event.
* this is not the same relation as before.
*/
*/
if
(
rel
==
NULL
||
rel
->
rd_id
!=
event
->
dte_relid
)
for
(
i
=
0
;
i
<
event
->
dte_n_items
;
i
++
)
{
{
if
(
rel
)
if
(
event
->
dte_item
[
i
].
dti_state
&
TRIGGER_DEFERRED_DONE
)
heap_close
(
rel
,
NoLock
);
continue
;
if
(
finfo
)
pfree
(
finfo
);
/*
/*
*
We assume that an appropriate lock is still held by th
e
*
This trigger item hasn't been called yet. Check if w
e
*
executor, so grab no new lock here
.
*
should call it now
.
*/
*/
rel
=
heap_open
(
event
->
dte_relid
,
NoLock
);
if
(
immediate_only
&&
deferredTriggerCheckState
(
event
->
dte_item
[
i
].
dti_tgoid
,
event
->
dte_item
[
i
].
dti_state
))
{
still_deferred_ones
=
true
;
continue
;
}
/*
/*
*
Allocate space to cache fmgr lookup info for triggers
*
So let's fire it... but first, open the correct relation
*
of this relation
.
*
if this is not the same relation as before
.
*/
*/
finfo
=
(
FmgrInfo
*
)
if
(
rel
==
NULL
||
rel
->
rd_id
!=
event
->
dte_relid
)
palloc
(
rel
->
trigdesc
->
numtriggers
*
sizeof
(
FmgrInfo
));
{
MemSet
(
finfo
,
0
,
if
(
rel
)
rel
->
trigdesc
->
numtriggers
*
sizeof
(
FmgrInfo
));
heap_close
(
rel
,
NoLock
);
}
if
(
finfo
)
pfree
(
finfo
);
DeferredTriggerExecute
(
event
,
i
,
rel
,
finfo
,
per_tuple_context
);
/*
* We assume that an appropriate lock is still held by the
* executor, so grab no new lock here.
*/
rel
=
heap_open
(
event
->
dte_relid
,
NoLock
);
event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_DONE
;
/*
* Allocate space to cache fmgr lookup info for triggers
* of this relation.
*/
finfo
=
(
FmgrInfo
*
)
palloc
(
rel
->
trigdesc
->
numtriggers
*
sizeof
(
FmgrInfo
));
MemSet
(
finfo
,
0
,
rel
->
trigdesc
->
numtriggers
*
sizeof
(
FmgrInfo
));
}
DeferredTriggerExecute
(
event
,
i
,
rel
,
finfo
,
per_tuple_context
);
event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_DONE
;
}
/* end loop over items within event */
}
}
/*
/*
* Remember in the event itself if all trigger items are done.
* If it's now completely done, throw it away.
*
* NB: it's possible the trigger calls above added more events to the
* queue, or that calls we will do later will want to add more,
* so we have to be careful about maintaining list validity here.
*/
*/
if
(
!
still_deferred_ones
)
next_event
=
event
->
dte_next
;
event
->
dte_event
|=
TRIGGER_DEFERRED_DONE
;
if
(
still_deferred_ones
)
{
/* Not done, keep in list */
prev_event
=
event
;
}
else
{
/* Done */
if
(
immediate_only
)
{
/* delink it from list and free it */
if
(
prev_event
)
prev_event
->
dte_next
=
next_event
;
else
deftrig_events
=
next_event
;
pfree
(
event
);
}
else
{
/*
* We will clean up later, but just for paranoia's sake,
* mark the event done.
*/
event
->
dte_event
|=
TRIGGER_DEFERRED_DONE
;
}
}
event
=
next_event
;
}
}
/* Update list tail pointer in case we just deleted tail event */
deftrig_event_tail
=
prev_event
;
/* Release working resources */
if
(
rel
)
if
(
rel
)
heap_close
(
rel
,
NoLock
);
heap_close
(
rel
,
NoLock
);
if
(
finfo
)
if
(
finfo
)
...
@@ -1649,7 +1648,6 @@ DeferredTriggerBeginXact(void)
...
@@ -1649,7 +1648,6 @@ DeferredTriggerBeginXact(void)
MemoryContextSwitchTo
(
oldcxt
);
MemoryContextSwitchTo
(
oldcxt
);
deftrig_n_events
=
0
;
deftrig_events
=
NULL
;
deftrig_events
=
NULL
;
deftrig_event_tail
=
NULL
;
deftrig_event_tail
=
NULL
;
}
}
...
@@ -1986,9 +1984,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
...
@@ -1986,9 +1984,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* Called by ExecAR...Triggers() to add the event to the queue.
* Called by ExecAR...Triggers() to add the event to the queue.
*
*
* NOTE: should be called only if we've determined that an event must
* NOTE: should be called only if we've determined that an event must
* be added to the queue. We must save *all* events if there is either
* be added to the queue.
* an UPDATE or a DELETE deferred trigger; see uses of
* deferredTriggerGetPreviousEvent.
* ----------
* ----------
*/
*/
static
void
static
void
...
@@ -1999,7 +1995,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
...
@@ -1999,7 +1995,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
TriggerDesc
*
trigdesc
=
relinfo
->
ri_TrigDesc
;
MemoryContext
oldcxt
;
MemoryContext
oldcxt
;
DeferredTriggerEvent
new_event
;
DeferredTriggerEvent
new_event
;
DeferredTriggerEvent
prev_event
;
int
new_size
;
int
new_size
;
int
i
;
int
i
;
int
ntriggers
;
int
ntriggers
;
...
@@ -2060,26 +2055,12 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
...
@@ -2060,26 +2055,12 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
switch
(
event
&
TRIGGER_EVENT_OPMASK
)
switch
(
event
&
TRIGGER_EVENT_OPMASK
)
{
{
case
TRIGGER_EVENT_INSERT
:
case
TRIGGER_EVENT_INSERT
:
new_event
->
dte_event
|=
TRIGGER_DEFERRED_ROW_INSERTED
;
/* nothing to do */
new_event
->
dte_event
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
break
;
break
;
case
TRIGGER_EVENT_UPDATE
:
case
TRIGGER_EVENT_UPDATE
:
/*
/*
* On UPDATE check if the tuple updated has been inserted or a
* Check if one of the referenced keys is changed.
* foreign referenced key value that's changing now has been
* updated once before in this transaction.
*/
if
(
!
TransactionIdEquals
(
oldtup
->
t_data
->
t_xmin
,
GetCurrentTransactionId
()))
prev_event
=
NULL
;
else
prev_event
=
deferredTriggerGetPreviousEvent
(
rel
->
rd_id
,
&
oldctid
);
/*
* Now check if one of the referenced keys is changed.
*/
*/
for
(
i
=
0
;
i
<
ntriggers
;
i
++
)
for
(
i
=
0
;
i
<
ntriggers
;
i
++
)
{
{
...
@@ -2120,109 +2101,21 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
...
@@ -2120,109 +2101,21 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
{
{
/*
/*
* The key hasn't changed, so no need later to invoke
* The key hasn't changed, so no need later to invoke
* the trigger at all. But remember other states from
* the trigger at all.
* the possible earlier event.
*/
*/
new_event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_DONE
;
new_event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_DONE
;
if
(
prev_event
)
{
if
(
prev_event
->
dte_event
&
TRIGGER_DEFERRED_ROW_INSERTED
)
{
/*
* This is a row inserted during our
* transaction. So any key value is considered
* changed.
*/
new_event
->
dte_event
|=
TRIGGER_DEFERRED_ROW_INSERTED
;
new_event
->
dte_event
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
new_event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
}
else
{
/*
* This is a row, previously updated. So if
* this key has been changed before, we still
* remember that it happened.
*/
if
(
prev_event
->
dte_item
[
i
].
dti_state
&
TRIGGER_DEFERRED_KEY_CHANGED
)
{
new_event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
new_event
->
dte_event
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
}
}
}
}
else
{
/*
* Bomb out if this key has been changed before.
* Otherwise remember that we do so.
*/
if
(
prev_event
)
{
if
(
prev_event
->
dte_event
&
TRIGGER_DEFERRED_ROW_INSERTED
)
elog
(
ERROR
,
"triggered data change violation "
"on relation
\"
%s
\"
"
,
DatumGetCString
(
DirectFunctionCall1
(
nameout
,
NameGetDatum
(
&
(
rel
->
rd_rel
->
relname
)))));
if
(
prev_event
->
dte_item
[
i
].
dti_state
&
TRIGGER_DEFERRED_KEY_CHANGED
)
elog
(
ERROR
,
"triggered data change violation "
"on relation
\"
%s
\"
"
,
DatumGetCString
(
DirectFunctionCall1
(
nameout
,
NameGetDatum
(
&
(
rel
->
rd_rel
->
relname
)))));
}
/*
* This is the first change to this key, so let it
* happen.
*/
new_event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
new_event
->
dte_event
|=
TRIGGER_DEFERRED_KEY_CHANGED
;
}
}
}
}
break
;
break
;
case
TRIGGER_EVENT_DELETE
:
case
TRIGGER_EVENT_DELETE
:
/* nothing to do */
/*
* On DELETE check if the tuple deleted has been inserted or a
* possibly referenced key value has changed in this
* transaction.
*/
if
(
!
TransactionIdEquals
(
oldtup
->
t_data
->
t_xmin
,
GetCurrentTransactionId
()))
break
;
/*
* Look at the previous event to the same tuple.
*/
prev_event
=
deferredTriggerGetPreviousEvent
(
rel
->
rd_id
,
&
oldctid
);
if
(
prev_event
->
dte_event
&
TRIGGER_DEFERRED_KEY_CHANGED
)
elog
(
ERROR
,
"triggered data change violation "
"on relation
\"
%s
\"
"
,
DatumGetCString
(
DirectFunctionCall1
(
nameout
,
NameGetDatum
(
&
(
rel
->
rd_rel
->
relname
)))));
break
;
break
;
}
}
/*
/*
* A
nything's fine up to here. A
dd the new event to the queue.
* Add the new event to the queue.
*/
*/
oldcxt
=
MemoryContextSwitchTo
(
deftrig_cxt
);
deferredTriggerAddEvent
(
new_event
);
deferredTriggerAddEvent
(
new_event
);
MemoryContextSwitchTo
(
oldcxt
);
}
}
src/include/commands/trigger.h
View file @
7c50767f
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: trigger.h,v 1.3
1 2001/11/12 00:46:3
6 tgl Exp $
* $Id: trigger.h,v 1.3
2 2001/11/16 16:31:1
6 tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -50,9 +50,6 @@ typedef struct TriggerData
...
@@ -50,9 +50,6 @@ typedef struct TriggerData
#define TRIGGER_DEFERRED_DEFERRABLE 0x00000040
#define TRIGGER_DEFERRED_DEFERRABLE 0x00000040
#define TRIGGER_DEFERRED_INITDEFERRED 0x00000080
#define TRIGGER_DEFERRED_INITDEFERRED 0x00000080
#define TRIGGER_DEFERRED_HAS_BEFORE 0x00000100
#define TRIGGER_DEFERRED_HAS_BEFORE 0x00000100
#define TRIGGER_DEFERRED_ROW_INSERTED 0x00000200
#define TRIGGER_DEFERRED_KEY_CHANGED 0x00000400
#define TRIGGER_DEFERRED_MASK 0x000007F0
#define TRIGGER_FIRED_BY_INSERT(event) \
#define TRIGGER_FIRED_BY_INSERT(event) \
(((TriggerEvent) (event) & TRIGGER_EVENT_OPMASK) == \
(((TriggerEvent) (event) & TRIGGER_EVENT_OPMASK) == \
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment