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
c9fe1283
Commit
c9fe1283
authored
Jan 22, 2001
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up per-tuple memory leaks in trigger firing and plpgsql
expression evaluation.
parent
59a3a401
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
160 additions
and
147 deletions
+160
-147
src/backend/commands/copy.c
src/backend/commands/copy.c
+6
-3
src/backend/commands/trigger.c
src/backend/commands/trigger.c
+57
-30
src/backend/executor/execMain.c
src/backend/executor/execMain.c
+33
-29
src/backend/executor/execUtils.c
src/backend/executor/execUtils.c
+23
-15
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeIndexscan.c
+1
-10
src/include/commands/trigger.h
src/include/commands/trigger.h
+9
-6
src/include/executor/executor.h
src/include/executor/executor.h
+19
-1
src/include/nodes/execnodes.h
src/include/nodes/execnodes.h
+2
-2
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_exec.c
+10
-51
No files found.
src/backend/commands/copy.c
View file @
c9fe1283
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.13
0 2001/01/19 06:54:57
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.13
1 2001/01/22 00:50:06
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -705,6 +705,9 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
...
@@ -705,6 +705,9 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
lineno
++
;
lineno
++
;
/* Reset the per-output-tuple exprcontext */
ResetPerTupleExprContext
(
estate
);
/* Initialize all values for row to NULL */
/* Initialize all values for row to NULL */
MemSet
(
values
,
0
,
attr_count
*
sizeof
(
Datum
));
MemSet
(
values
,
0
,
attr_count
*
sizeof
(
Datum
));
MemSet
(
nulls
,
'n'
,
attr_count
*
sizeof
(
char
));
MemSet
(
nulls
,
'n'
,
attr_count
*
sizeof
(
char
));
...
@@ -861,7 +864,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
...
@@ -861,7 +864,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
{
{
HeapTuple
newtuple
;
HeapTuple
newtuple
;
newtuple
=
ExecBRInsertTriggers
(
rel
,
tuple
);
newtuple
=
ExecBRInsertTriggers
(
estate
,
rel
,
tuple
);
if
(
newtuple
==
NULL
)
/* "do nothing" */
if
(
newtuple
==
NULL
)
/* "do nothing" */
skip_tuple
=
true
;
skip_tuple
=
true
;
...
@@ -895,7 +898,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
...
@@ -895,7 +898,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
/* AFTER ROW INSERT Triggers */
/* AFTER ROW INSERT Triggers */
if
(
rel
->
trigdesc
&&
if
(
rel
->
trigdesc
&&
rel
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_INSERT
]
>
0
)
rel
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_INSERT
]
>
0
)
ExecARInsertTriggers
(
rel
,
tuple
);
ExecARInsertTriggers
(
estate
,
rel
,
tuple
);
}
}
for
(
i
=
0
;
i
<
attr_count
;
i
++
)
for
(
i
=
0
;
i
<
attr_count
;
i
++
)
...
...
src/backend/commands/trigger.c
View file @
c9fe1283
...
@@ -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.8
2 2000/12/18 00:44:46
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.8
3 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -36,7 +36,8 @@ static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
...
@@ -36,7 +36,8 @@ static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
static
HeapTuple
GetTupleForTrigger
(
EState
*
estate
,
ItemPointer
tid
,
static
HeapTuple
GetTupleForTrigger
(
EState
*
estate
,
ItemPointer
tid
,
TupleTableSlot
**
newSlot
);
TupleTableSlot
**
newSlot
);
static
HeapTuple
ExecCallTriggerFunc
(
Trigger
*
trigger
,
static
HeapTuple
ExecCallTriggerFunc
(
Trigger
*
trigger
,
TriggerData
*
trigdata
);
TriggerData
*
trigdata
,
MemoryContext
per_tuple_context
);
static
void
DeferredTriggerSaveEvent
(
Relation
rel
,
int
event
,
static
void
DeferredTriggerSaveEvent
(
Relation
rel
,
int
event
,
HeapTuple
oldtup
,
HeapTuple
newtup
);
HeapTuple
oldtup
,
HeapTuple
newtup
);
...
@@ -831,10 +832,13 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
...
@@ -831,10 +832,13 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
}
}
static
HeapTuple
static
HeapTuple
ExecCallTriggerFunc
(
Trigger
*
trigger
,
TriggerData
*
trigdata
)
ExecCallTriggerFunc
(
Trigger
*
trigger
,
TriggerData
*
trigdata
,
MemoryContext
per_tuple_context
)
{
{
FunctionCallInfoData
fcinfo
;
FunctionCallInfoData
fcinfo
;
Datum
result
;
Datum
result
;
MemoryContext
oldContext
;
/*
/*
* Fmgr lookup info is cached in the Trigger structure,
* Fmgr lookup info is cached in the Trigger structure,
...
@@ -843,6 +847,14 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
...
@@ -843,6 +847,14 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
if
(
trigger
->
tgfunc
.
fn_oid
==
InvalidOid
)
if
(
trigger
->
tgfunc
.
fn_oid
==
InvalidOid
)
fmgr_info
(
trigger
->
tgfoid
,
&
trigger
->
tgfunc
);
fmgr_info
(
trigger
->
tgfoid
,
&
trigger
->
tgfunc
);
/*
* Do the function evaluation in the per-tuple memory context,
* so that leaked memory will be reclaimed once per tuple.
* Note in particular that any new tuple created by the trigger function
* will live till the end of the tuple cycle.
*/
oldContext
=
MemoryContextSwitchTo
(
per_tuple_context
);
/*
/*
* Call the function, passing no arguments but setting a context.
* Call the function, passing no arguments but setting a context.
*/
*/
...
@@ -853,6 +865,8 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
...
@@ -853,6 +865,8 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
result
=
FunctionCallInvoke
(
&
fcinfo
);
result
=
FunctionCallInvoke
(
&
fcinfo
);
MemoryContextSwitchTo
(
oldContext
);
/*
/*
* Trigger protocol allows function to return a null pointer,
* Trigger protocol allows function to return a null pointer,
* but NOT to set the isnull result flag.
* but NOT to set the isnull result flag.
...
@@ -865,7 +879,7 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
...
@@ -865,7 +879,7 @@ ExecCallTriggerFunc(Trigger *trigger, TriggerData *trigdata)
}
}
HeapTuple
HeapTuple
ExecBRInsertTriggers
(
Relation
rel
,
HeapTuple
trigtuple
)
ExecBRInsertTriggers
(
EState
*
estate
,
Relation
rel
,
HeapTuple
trigtuple
)
{
{
int
ntrigs
=
rel
->
trigdesc
->
n_before_row
[
TRIGGER_EVENT_INSERT
];
int
ntrigs
=
rel
->
trigdesc
->
n_before_row
[
TRIGGER_EVENT_INSERT
];
Trigger
**
trigger
=
rel
->
trigdesc
->
tg_before_row
[
TRIGGER_EVENT_INSERT
];
Trigger
**
trigger
=
rel
->
trigdesc
->
tg_before_row
[
TRIGGER_EVENT_INSERT
];
...
@@ -884,20 +898,20 @@ ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
...
@@ -884,20 +898,20 @@ ExecBRInsertTriggers(Relation rel, HeapTuple trigtuple)
continue
;
continue
;
LocTriggerData
.
tg_trigtuple
=
oldtuple
=
newtuple
;
LocTriggerData
.
tg_trigtuple
=
oldtuple
=
newtuple
;
LocTriggerData
.
tg_trigger
=
trigger
[
i
];
LocTriggerData
.
tg_trigger
=
trigger
[
i
];
newtuple
=
ExecCallTriggerFunc
(
trigger
[
i
],
&
LocTriggerData
);
newtuple
=
ExecCallTriggerFunc
(
trigger
[
i
],
&
LocTriggerData
,
GetPerTupleMemoryContext
(
estate
));
if
(
oldtuple
!=
newtuple
&&
oldtuple
!=
trigtuple
)
heap_freetuple
(
oldtuple
);
if
(
newtuple
==
NULL
)
if
(
newtuple
==
NULL
)
break
;
break
;
else
if
(
oldtuple
!=
newtuple
&&
oldtuple
!=
trigtuple
)
heap_freetuple
(
oldtuple
);
}
}
return
newtuple
;
return
newtuple
;
}
}
void
void
ExecARInsertTriggers
(
Relation
rel
,
HeapTuple
trigtuple
)
ExecARInsertTriggers
(
EState
*
estate
,
Relation
rel
,
HeapTuple
trigtuple
)
{
{
DeferredTriggerSaveEvent
(
rel
,
TRIGGER_EVENT_INSERT
,
NULL
,
trigtuple
);
DeferredTriggerSaveEvent
(
rel
,
TRIGGER_EVENT_INSERT
,
NULL
,
trigtuple
);
return
;
}
}
bool
bool
...
@@ -926,7 +940,8 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
...
@@ -926,7 +940,8 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
continue
;
continue
;
LocTriggerData
.
tg_trigtuple
=
trigtuple
;
LocTriggerData
.
tg_trigtuple
=
trigtuple
;
LocTriggerData
.
tg_trigger
=
trigger
[
i
];
LocTriggerData
.
tg_trigger
=
trigger
[
i
];
newtuple
=
ExecCallTriggerFunc
(
trigger
[
i
],
&
LocTriggerData
);
newtuple
=
ExecCallTriggerFunc
(
trigger
[
i
],
&
LocTriggerData
,
GetPerTupleMemoryContext
(
estate
));
if
(
newtuple
==
NULL
)
if
(
newtuple
==
NULL
)
break
;
break
;
if
(
newtuple
!=
trigtuple
)
if
(
newtuple
!=
trigtuple
)
...
@@ -944,7 +959,7 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
...
@@ -944,7 +959,7 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
tupleid
,
NULL
);
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
tupleid
,
NULL
);
DeferredTriggerSaveEvent
(
rel
,
TRIGGER_EVENT_DELETE
,
trigtuple
,
NULL
);
DeferredTriggerSaveEvent
(
rel
,
TRIGGER_EVENT_DELETE
,
trigtuple
,
NULL
);
return
;
heap_freetuple
(
trigtuple
)
;
}
}
HeapTuple
HeapTuple
...
@@ -981,11 +996,12 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
...
@@ -981,11 +996,12 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
LocTriggerData
.
tg_trigtuple
=
trigtuple
;
LocTriggerData
.
tg_trigtuple
=
trigtuple
;
LocTriggerData
.
tg_newtuple
=
oldtuple
=
newtuple
;
LocTriggerData
.
tg_newtuple
=
oldtuple
=
newtuple
;
LocTriggerData
.
tg_trigger
=
trigger
[
i
];
LocTriggerData
.
tg_trigger
=
trigger
[
i
];
newtuple
=
ExecCallTriggerFunc
(
trigger
[
i
],
&
LocTriggerData
);
newtuple
=
ExecCallTriggerFunc
(
trigger
[
i
],
&
LocTriggerData
,
GetPerTupleMemoryContext
(
estate
));
if
(
oldtuple
!=
newtuple
&&
oldtuple
!=
intuple
)
heap_freetuple
(
oldtuple
);
if
(
newtuple
==
NULL
)
if
(
newtuple
==
NULL
)
break
;
break
;
else
if
(
oldtuple
!=
newtuple
&&
oldtuple
!=
intuple
)
heap_freetuple
(
oldtuple
);
}
}
heap_freetuple
(
trigtuple
);
heap_freetuple
(
trigtuple
);
return
newtuple
;
return
newtuple
;
...
@@ -998,7 +1014,7 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
...
@@ -998,7 +1014,7 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
tupleid
,
NULL
);
HeapTuple
trigtuple
=
GetTupleForTrigger
(
estate
,
tupleid
,
NULL
);
DeferredTriggerSaveEvent
(
rel
,
TRIGGER_EVENT_UPDATE
,
trigtuple
,
newtuple
);
DeferredTriggerSaveEvent
(
rel
,
TRIGGER_EVENT_UPDATE
,
trigtuple
,
newtuple
);
return
;
heap_freetuple
(
trigtuple
)
;
}
}
...
@@ -1236,7 +1252,7 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
...
@@ -1236,7 +1252,7 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
}
}
elog
(
ERROR
,
elog
(
ERROR
,
"deferredTriggerGetPreviousEvent
()
: event for tuple %s not found"
,
"deferredTriggerGetPreviousEvent: event for tuple %s not found"
,
DatumGetCString
(
DirectFunctionCall1
(
tidout
,
PointerGetDatum
(
ctid
))));
DatumGetCString
(
DirectFunctionCall1
(
tidout
,
PointerGetDatum
(
ctid
))));
return
NULL
;
return
NULL
;
}
}
...
@@ -1250,7 +1266,8 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
...
@@ -1250,7 +1266,8 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
* ----------
* ----------
*/
*/
static
void
static
void
deferredTriggerExecute
(
DeferredTriggerEvent
event
,
int
itemno
)
deferredTriggerExecute
(
DeferredTriggerEvent
event
,
int
itemno
,
MemoryContext
per_tuple_context
)
{
{
Relation
rel
;
Relation
rel
;
TriggerData
LocTriggerData
;
TriggerData
LocTriggerData
;
...
@@ -1271,7 +1288,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
...
@@ -1271,7 +1288,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
ItemPointerCopy
(
&
(
event
->
dte_oldctid
),
&
(
oldtuple
.
t_self
));
ItemPointerCopy
(
&
(
event
->
dte_oldctid
),
&
(
oldtuple
.
t_self
));
heap_fetch
(
rel
,
SnapshotAny
,
&
oldtuple
,
&
oldbuffer
);
heap_fetch
(
rel
,
SnapshotAny
,
&
oldtuple
,
&
oldbuffer
);
if
(
!
oldtuple
.
t_data
)
if
(
!
oldtuple
.
t_data
)
elog
(
ERROR
,
"deferredTriggerExecute
()
: failed to fetch old tuple"
);
elog
(
ERROR
,
"deferredTriggerExecute: failed to fetch old tuple"
);
}
}
if
(
ItemPointerIsValid
(
&
(
event
->
dte_newctid
)))
if
(
ItemPointerIsValid
(
&
(
event
->
dte_newctid
)))
...
@@ -1279,7 +1296,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
...
@@ -1279,7 +1296,7 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
ItemPointerCopy
(
&
(
event
->
dte_newctid
),
&
(
newtuple
.
t_self
));
ItemPointerCopy
(
&
(
event
->
dte_newctid
),
&
(
newtuple
.
t_self
));
heap_fetch
(
rel
,
SnapshotAny
,
&
newtuple
,
&
newbuffer
);
heap_fetch
(
rel
,
SnapshotAny
,
&
newtuple
,
&
newbuffer
);
if
(
!
newtuple
.
t_data
)
if
(
!
newtuple
.
t_data
)
elog
(
ERROR
,
"deferredTriggerExecute
()
: failed to fetch new tuple"
);
elog
(
ERROR
,
"deferredTriggerExecute: failed to fetch new tuple"
);
}
}
/* ----------
/* ----------
...
@@ -1320,7 +1337,9 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
...
@@ -1320,7 +1337,9 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno)
* updated tuple.
* updated tuple.
* ----------
* ----------
*/
*/
rettuple
=
ExecCallTriggerFunc
(
LocTriggerData
.
tg_trigger
,
&
LocTriggerData
);
rettuple
=
ExecCallTriggerFunc
(
LocTriggerData
.
tg_trigger
,
&
LocTriggerData
,
per_tuple_context
);
if
(
rettuple
!=
NULL
&&
rettuple
!=
&
oldtuple
&&
rettuple
!=
&
newtuple
)
if
(
rettuple
!=
NULL
&&
rettuple
!=
&
oldtuple
&&
rettuple
!=
&
newtuple
)
heap_freetuple
(
rettuple
);
heap_freetuple
(
rettuple
);
...
@@ -1359,6 +1378,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
...
@@ -1359,6 +1378,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
int
still_deferred_ones
;
int
still_deferred_ones
;
int
eventno
=
-
1
;
int
eventno
=
-
1
;
int
i
;
int
i
;
MemoryContext
per_tuple_context
;
/* ----------
/* ----------
* For now we process all events - to speedup transaction blocks
* For now we process all events - to speedup transaction blocks
...
@@ -1369,10 +1389,21 @@ deferredTriggerInvokeEvents(bool immediate_only)
...
@@ -1369,10 +1389,21 @@ deferredTriggerInvokeEvents(bool immediate_only)
* SET CONSTRAINTS ... command finishes and calls EndQuery.
* SET CONSTRAINTS ... command finishes and calls EndQuery.
* ----------
* ----------
*/
*/
/* Make a per-tuple memory context for trigger function calls */
per_tuple_context
=
AllocSetContextCreate
(
CurrentMemoryContext
,
"DeferredTriggerTupleContext"
,
0
,
ALLOCSET_DEFAULT_INITSIZE
,
ALLOCSET_DEFAULT_MAXSIZE
);
foreach
(
el
,
deftrig_events
)
foreach
(
el
,
deftrig_events
)
{
{
eventno
++
;
eventno
++
;
MemoryContextReset
(
per_tuple_context
);
/* ----------
/* ----------
* Get the event and check if it is completely done.
* Get the event and check if it is completely done.
* ----------
* ----------
...
@@ -1409,7 +1440,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
...
@@ -1409,7 +1440,7 @@ deferredTriggerInvokeEvents(bool immediate_only)
* So let's fire it...
* So let's fire it...
* ----------
* ----------
*/
*/
deferredTriggerExecute
(
event
,
i
);
deferredTriggerExecute
(
event
,
i
,
per_tuple_context
);
event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_DONE
;
event
->
dte_item
[
i
].
dti_state
|=
TRIGGER_DEFERRED_DONE
;
}
}
...
@@ -1421,6 +1452,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
...
@@ -1421,6 +1452,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
if
(
!
still_deferred_ones
)
if
(
!
still_deferred_ones
)
event
->
dte_event
|=
TRIGGER_DEFERRED_DONE
;
event
->
dte_event
|=
TRIGGER_DEFERRED_DONE
;
}
}
MemoryContextDelete
(
per_tuple_context
);
}
}
...
@@ -1866,13 +1899,10 @@ DeferredTriggerSaveEvent(Relation rel, int event,
...
@@ -1866,13 +1899,10 @@ DeferredTriggerSaveEvent(Relation rel, int event,
* Check if we're interested in this row at all
* Check if we're interested in this row at all
* ----------
* ----------
*/
*/
if
(
rel
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_INSERT
]
==
0
&&
ntriggers
=
rel
->
trigdesc
->
n_after_row
[
event
];
rel
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_UPDATE
]
==
0
&&
if
(
ntriggers
<=
0
)
rel
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_DELETE
]
==
0
&&
rel
->
trigdesc
->
n_before_row
[
TRIGGER_EVENT_INSERT
]
==
0
&&
rel
->
trigdesc
->
n_before_row
[
TRIGGER_EVENT_UPDATE
]
==
0
&&
rel
->
trigdesc
->
n_before_row
[
TRIGGER_EVENT_DELETE
]
==
0
)
return
;
return
;
triggers
=
rel
->
trigdesc
->
tg_after_row
[
event
];
/* ----------
/* ----------
* Get the CTID's of OLD and NEW
* Get the CTID's of OLD and NEW
...
@@ -1893,9 +1923,6 @@ DeferredTriggerSaveEvent(Relation rel, int event,
...
@@ -1893,9 +1923,6 @@ DeferredTriggerSaveEvent(Relation rel, int event,
*/
*/
oldcxt
=
MemoryContextSwitchTo
(
deftrig_cxt
);
oldcxt
=
MemoryContextSwitchTo
(
deftrig_cxt
);
ntriggers
=
rel
->
trigdesc
->
n_after_row
[
event
];
triggers
=
rel
->
trigdesc
->
tg_after_row
[
event
];
new_size
=
sizeof
(
DeferredTriggerEventData
)
+
new_size
=
sizeof
(
DeferredTriggerEventData
)
+
ntriggers
*
sizeof
(
DeferredTriggerEventItem
);
ntriggers
*
sizeof
(
DeferredTriggerEventItem
);
...
...
src/backend/executor/execMain.c
View file @
c9fe1283
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.13
4 2001/01/01 21:22:54
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.13
5 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -941,11 +941,13 @@ ExecutePlan(EState *estate,
...
@@ -941,11 +941,13 @@ ExecutePlan(EState *estate,
/*
/*
* Loop until we've processed the proper number of tuples from the
* Loop until we've processed the proper number of tuples from the
* plan.
.
* plan.
*/
*/
for
(;;)
for
(;;)
{
{
/* Reset the per-output-tuple exprcontext */
ResetPerTupleExprContext
(
estate
);
/*
/*
* Execute the plan and obtain a tuple
* Execute the plan and obtain a tuple
...
@@ -1217,16 +1219,21 @@ ExecAppend(TupleTableSlot *slot,
...
@@ -1217,16 +1219,21 @@ ExecAppend(TupleTableSlot *slot,
{
{
HeapTuple
newtuple
;
HeapTuple
newtuple
;
newtuple
=
ExecBRInsertTriggers
(
resultRelationDesc
,
tuple
);
newtuple
=
ExecBRInsertTriggers
(
estate
,
resultRelationDesc
,
tuple
);
if
(
newtuple
==
NULL
)
/* "do nothing" */
if
(
newtuple
==
NULL
)
/* "do nothing" */
return
;
return
;
if
(
newtuple
!=
tuple
)
/* modified by Trigger(s) */
if
(
newtuple
!=
tuple
)
/* modified by Trigger(s) */
{
{
Assert
(
slot
->
ttc_shouldFree
);
/*
heap_freetuple
(
tuple
);
* Insert modified tuple into tuple table slot, replacing the
slot
->
val
=
tuple
=
newtuple
;
* original. We assume that it was allocated in per-tuple
* memory context, and therefore will go away by itself.
* The tuple table slot should not try to clear it.
*/
ExecStoreTuple
(
newtuple
,
slot
,
InvalidBuffer
,
false
);
tuple
=
newtuple
;
}
}
}
}
...
@@ -1257,8 +1264,9 @@ ExecAppend(TupleTableSlot *slot,
...
@@ -1257,8 +1264,9 @@ ExecAppend(TupleTableSlot *slot,
ExecInsertIndexTuples
(
slot
,
&
(
tuple
->
t_self
),
estate
,
false
);
ExecInsertIndexTuples
(
slot
,
&
(
tuple
->
t_self
),
estate
,
false
);
/* AFTER ROW INSERT Triggers */
/* AFTER ROW INSERT Triggers */
if
(
resultRelationDesc
->
trigdesc
)
if
(
resultRelationDesc
->
trigdesc
&&
ExecARInsertTriggers
(
resultRelationDesc
,
tuple
);
resultRelationDesc
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_INSERT
]
>
0
)
ExecARInsertTriggers
(
estate
,
resultRelationDesc
,
tuple
);
}
}
/* ----------------------------------------------------------------
/* ----------------------------------------------------------------
...
@@ -1343,9 +1351,9 @@ ldelete:;
...
@@ -1343,9 +1351,9 @@ ldelete:;
*/
*/
/* AFTER ROW DELETE Triggers */
/* AFTER ROW DELETE Triggers */
if
(
resultRelationDesc
->
trigdesc
)
if
(
resultRelationDesc
->
trigdesc
&&
resultRelationDesc
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_DELETE
]
>
0
)
ExecARDeleteTriggers
(
estate
,
tupleid
);
ExecARDeleteTriggers
(
estate
,
tupleid
);
}
}
/* ----------------------------------------------------------------
/* ----------------------------------------------------------------
...
@@ -1404,9 +1412,14 @@ ExecReplace(TupleTableSlot *slot,
...
@@ -1404,9 +1412,14 @@ ExecReplace(TupleTableSlot *slot,
if
(
newtuple
!=
tuple
)
/* modified by Trigger(s) */
if
(
newtuple
!=
tuple
)
/* modified by Trigger(s) */
{
{
Assert
(
slot
->
ttc_shouldFree
);
/*
heap_freetuple
(
tuple
);
* Insert modified tuple into tuple table slot, replacing the
slot
->
val
=
tuple
=
newtuple
;
* original. We assume that it was allocated in per-tuple
* memory context, and therefore will go away by itself.
* The tuple table slot should not try to clear it.
*/
ExecStoreTuple
(
newtuple
,
slot
,
InvalidBuffer
,
false
);
tuple
=
newtuple
;
}
}
}
}
...
@@ -1478,7 +1491,8 @@ lreplace:;
...
@@ -1478,7 +1491,8 @@ lreplace:;
ExecInsertIndexTuples
(
slot
,
&
(
tuple
->
t_self
),
estate
,
true
);
ExecInsertIndexTuples
(
slot
,
&
(
tuple
->
t_self
),
estate
,
true
);
/* AFTER ROW UPDATE Triggers */
/* AFTER ROW UPDATE Triggers */
if
(
resultRelationDesc
->
trigdesc
)
if
(
resultRelationDesc
->
trigdesc
&&
resultRelationDesc
->
trigdesc
->
n_after_row
[
TRIGGER_EVENT_UPDATE
]
>
0
)
ExecARUpdateTriggers
(
estate
,
tupleid
,
tuple
);
ExecARUpdateTriggers
(
estate
,
tupleid
,
tuple
);
}
}
...
@@ -1514,19 +1528,9 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
...
@@ -1514,19 +1528,9 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
/*
/*
* We will use the EState's per-tuple context for evaluating constraint
* We will use the EState's per-tuple context for evaluating constraint
* expressions. Create it if it's not already there; if it is, reset it
* expressions (creating it if it's not already there).
* to free previously-used storage.
*/
*/
econtext
=
estate
->
es_per_tuple_exprcontext
;
econtext
=
GetPerTupleExprContext
(
estate
);
if
(
econtext
==
NULL
)
{
oldContext
=
MemoryContextSwitchTo
(
estate
->
es_query_cxt
);
estate
->
es_per_tuple_exprcontext
=
econtext
=
MakeExprContext
(
NULL
,
estate
->
es_query_cxt
);
MemoryContextSwitchTo
(
oldContext
);
}
else
ResetExprContext
(
econtext
);
/* Arrange for econtext's scan tuple to be the tuple under test */
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext
->
ecxt_scantuple
=
slot
;
econtext
->
ecxt_scantuple
=
slot
;
...
...
src/backend/executor/execUtils.c
View file @
c9fe1283
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.7
0 2000/12/27 23:59:11
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.7
1 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -230,6 +230,26 @@ FreeExprContext(ExprContext *econtext)
...
@@ -230,6 +230,26 @@ FreeExprContext(ExprContext *econtext)
pfree
(
econtext
);
pfree
(
econtext
);
}
}
/*
* Build a per-output-tuple ExprContext for an EState.
*
* This is normally invoked via GetPerTupleExprContext() macro.
*/
ExprContext
*
MakePerTupleExprContext
(
EState
*
estate
)
{
if
(
estate
->
es_per_tuple_exprcontext
==
NULL
)
{
MemoryContext
oldContext
;
oldContext
=
MemoryContextSwitchTo
(
estate
->
es_query_cxt
);
estate
->
es_per_tuple_exprcontext
=
MakeExprContext
(
NULL
,
estate
->
es_query_cxt
);
MemoryContextSwitchTo
(
oldContext
);
}
return
estate
->
es_per_tuple_exprcontext
;
}
/* ----------------------------------------------------------------
/* ----------------------------------------------------------------
* Result slot tuple type and ProjectionInfo support
* Result slot tuple type and ProjectionInfo support
* ----------------------------------------------------------------
* ----------------------------------------------------------------
...
@@ -836,21 +856,9 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
...
@@ -836,21 +856,9 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
/*
/*
* We will use the EState's per-tuple context for evaluating predicates
* We will use the EState's per-tuple context for evaluating predicates
* and functional-index functions. Create it if it's not already there;
* and functional-index functions (creating it if it's not already there).
* if it is, reset it to free previously-used storage.
*/
*/
econtext
=
estate
->
es_per_tuple_exprcontext
;
econtext
=
GetPerTupleExprContext
(
estate
);
if
(
econtext
==
NULL
)
{
MemoryContext
oldContext
;
oldContext
=
MemoryContextSwitchTo
(
estate
->
es_query_cxt
);
estate
->
es_per_tuple_exprcontext
=
econtext
=
MakeExprContext
(
NULL
,
estate
->
es_query_cxt
);
MemoryContextSwitchTo
(
oldContext
);
}
else
ResetExprContext
(
econtext
);
/* Arrange for econtext's scan tuple to be the tuple under test */
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext
->
ecxt_scantuple
=
slot
;
econtext
->
ecxt_scantuple
=
slot
;
...
...
src/backend/executor/nodeIndexscan.c
View file @
c9fe1283
...
@@ -8,14 +8,12 @@
...
@@ -8,14 +8,12 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.5
4 2000/08/24 03:29:03
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.5
5 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
/*
/*
* INTERFACE ROUTINES
* INTERFACE ROUTINES
* ExecInsertIndexTuples inserts tuples into indices on result relation
*
* ExecIndexScan scans a relation using indices
* ExecIndexScan scans a relation using indices
* ExecIndexNext using index to retrieve next tuple
* ExecIndexNext using index to retrieve next tuple
* ExecInitIndexScan creates and initializes state info.
* ExecInitIndexScan creates and initializes state info.
...
@@ -23,16 +21,9 @@
...
@@ -23,16 +21,9 @@
* ExecEndIndexScan releases all storage.
* ExecEndIndexScan releases all storage.
* ExecIndexMarkPos marks scan position.
* ExecIndexMarkPos marks scan position.
* ExecIndexRestrPos restores scan position.
* ExecIndexRestrPos restores scan position.
*
* NOTES
* the code supporting ExecInsertIndexTuples should be
* collected and merged with the genam stuff.
*
*/
*/
#include "postgres.h"
#include "postgres.h"
#include "access/genam.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/heapam.h"
#include "executor/execdebug.h"
#include "executor/execdebug.h"
...
...
src/include/commands/trigger.h
View file @
c9fe1283
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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.2
2 2000/12/18 00:44:48
tgl Exp $
* $Id: trigger.h,v 1.2
3 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -89,13 +89,16 @@ extern void FreeTriggerDesc(TriggerDesc *trigdesc);
...
@@ -89,13 +89,16 @@ extern void FreeTriggerDesc(TriggerDesc *trigdesc);
extern
bool
equalTriggerDescs
(
TriggerDesc
*
trigdesc1
,
TriggerDesc
*
trigdesc2
);
extern
bool
equalTriggerDescs
(
TriggerDesc
*
trigdesc1
,
TriggerDesc
*
trigdesc2
);
extern
HeapTuple
ExecBRInsertTriggers
(
Relation
rel
,
HeapTuple
tuple
);
extern
HeapTuple
ExecBRInsertTriggers
(
EState
*
estate
,
extern
void
ExecARInsertTriggers
(
Relation
rel
,
HeapTuple
tuple
);
Relation
rel
,
HeapTuple
tuple
);
extern
void
ExecARInsertTriggers
(
EState
*
estate
,
Relation
rel
,
HeapTuple
tuple
);
extern
bool
ExecBRDeleteTriggers
(
EState
*
estate
,
ItemPointer
tupleid
);
extern
bool
ExecBRDeleteTriggers
(
EState
*
estate
,
ItemPointer
tupleid
);
extern
void
ExecARDeleteTriggers
(
EState
*
estate
,
ItemPointer
tupleid
);
extern
void
ExecARDeleteTriggers
(
EState
*
estate
,
ItemPointer
tupleid
);
extern
HeapTuple
ExecBRUpdateTriggers
(
EState
*
estate
,
ItemPointer
tupleid
,
HeapTuple
tuple
);
extern
HeapTuple
ExecBRUpdateTriggers
(
EState
*
estate
,
ItemPointer
tupleid
,
extern
void
ExecARUpdateTriggers
(
EState
*
estate
,
ItemPointer
tupleid
,
HeapTuple
tuple
);
HeapTuple
tuple
);
extern
void
ExecARUpdateTriggers
(
EState
*
estate
,
ItemPointer
tupleid
,
HeapTuple
tuple
);
/* ----------
/* ----------
...
...
src/include/executor/executor.h
View file @
c9fe1283
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: executor.h,v 1.5
3 2000/11/12 00:37:01
tgl Exp $
* $Id: executor.h,v 1.5
4 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -153,6 +153,24 @@ extern void FreeExprContext(ExprContext *econtext);
...
@@ -153,6 +153,24 @@ extern void FreeExprContext(ExprContext *econtext);
#define ResetExprContext(econtext) \
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
extern
ExprContext
*
MakePerTupleExprContext
(
EState
*
estate
);
/* Get an EState's per-output-tuple exprcontext, making it if first use */
#define GetPerTupleExprContext(estate) \
((estate)->es_per_tuple_exprcontext ? \
(estate)->es_per_tuple_exprcontext : \
MakePerTupleExprContext(estate))
#define GetPerTupleMemoryContext(estate) \
(GetPerTupleExprContext(estate)->ecxt_per_tuple_memory)
/* Reset an EState's per-output-tuple exprcontext, if one's been created */
#define ResetPerTupleExprContext(estate) \
do { \
if ((estate)->es_per_tuple_exprcontext) \
ResetExprContext((estate)->es_per_tuple_exprcontext); \
} while (0)
extern
void
ExecOpenIndices
(
ResultRelInfo
*
resultRelInfo
);
extern
void
ExecOpenIndices
(
ResultRelInfo
*
resultRelInfo
);
extern
void
ExecCloseIndices
(
ResultRelInfo
*
resultRelInfo
);
extern
void
ExecCloseIndices
(
ResultRelInfo
*
resultRelInfo
);
extern
void
ExecInsertIndexTuples
(
TupleTableSlot
*
slot
,
ItemPointer
tupleid
,
extern
void
ExecInsertIndexTuples
(
TupleTableSlot
*
slot
,
ItemPointer
tupleid
,
...
...
src/include/nodes/execnodes.h
View file @
c9fe1283
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: execnodes.h,v 1.5
3 2000/11/12 00:37:01
tgl Exp $
* $Id: execnodes.h,v 1.5
4 2001/01/22 00:50:07
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -251,7 +251,7 @@ typedef struct EState
...
@@ -251,7 +251,7 @@ typedef struct EState
MemoryContext
es_query_cxt
;
/* per-query context in which EState lives */
MemoryContext
es_query_cxt
;
/* per-query context in which EState lives */
/*
/*
* this ExprContext is for per-output-tuple operations, such as
* this ExprContext is for per-output-tuple operations, such as
* constraint checks and index-value computations. It
can
be reset
* constraint checks and index-value computations. It
will
be reset
* for each output tuple. Note that it will be created only if needed.
* for each output tuple. Note that it will be created only if needed.
*/
*/
ExprContext
*
es_per_tuple_exprcontext
;
ExprContext
*
es_per_tuple_exprcontext
;
...
...
src/pl/plpgsql/src/pl_exec.c
View file @
c9fe1283
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
* procedural language
* procedural language
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.3
5 2001/01/06 01:43:01
tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.3
6 2001/01/22 00:50:07
tgl Exp $
*
*
* This software is copyrighted by Jan Wieck - Hamburg.
* This software is copyrighted by Jan Wieck - Hamburg.
*
*
...
@@ -112,8 +112,6 @@ static void exec_prepare_plan(PLpgSQL_execstate * estate,
...
@@ -112,8 +112,6 @@ static void exec_prepare_plan(PLpgSQL_execstate * estate,
PLpgSQL_expr
*
expr
);
PLpgSQL_expr
*
expr
);
static
bool
exec_simple_check_node
(
Node
*
node
);
static
bool
exec_simple_check_node
(
Node
*
node
);
static
void
exec_simple_check_plan
(
PLpgSQL_expr
*
expr
);
static
void
exec_simple_check_plan
(
PLpgSQL_expr
*
expr
);
static
void
exec_eval_clear_fcache
(
Node
*
node
);
static
bool
exec_eval_clear_fcache_walker
(
Node
*
node
,
void
*
context
);
static
Datum
exec_eval_simple_expr
(
PLpgSQL_execstate
*
estate
,
static
Datum
exec_eval_simple_expr
(
PLpgSQL_execstate
*
estate
,
PLpgSQL_expr
*
expr
,
PLpgSQL_expr
*
expr
,
bool
*
isNull
,
bool
*
isNull
,
...
@@ -2530,10 +2528,17 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
...
@@ -2530,10 +2528,17 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
ParamListInfo
paramLI
;
ParamListInfo
paramLI
;
/* ----------
/* ----------
* Create a simple expression context to hold the arguments
* Create a simple expression context to hold the arguments.
*
* NOTE: we pass TopMemoryContext as the query-lifetime context for
* function cache nodes and suchlike allocations. This is necessary
* because that's where the expression tree itself is (it'll never be
* freed in this backend, and the function cache nodes must live as
* long as it does). The memory allocation for plpgsql's plan trees
* really needs to be redesigned...
* ----------
* ----------
*/
*/
econtext
=
MakeExprContext
(
NULL
,
T
ransactionCommand
Context
);
econtext
=
MakeExprContext
(
NULL
,
T
opMemory
Context
);
paramLI
=
(
ParamListInfo
)
palloc
((
expr
->
nparams
+
1
)
*
paramLI
=
(
ParamListInfo
)
palloc
((
expr
->
nparams
+
1
)
*
sizeof
(
ParamListInfoData
));
sizeof
(
ParamListInfoData
));
econtext
->
ecxt_param_list_info
=
paramLI
;
econtext
->
ecxt_param_list_info
=
paramLI
;
...
@@ -2601,12 +2606,6 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
...
@@ -2601,12 +2606,6 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
*/
*/
*
rettype
=
expr
->
plan_simple_type
;
*
rettype
=
expr
->
plan_simple_type
;
/* ----------
* Clear any function cache entries in the expression tree
* ----------
*/
exec_eval_clear_fcache
(
expr
->
plan_simple_expr
);
/* ----------
/* ----------
* Now call the executor to evaluate the expression
* Now call the executor to evaluate the expression
* ----------
* ----------
...
@@ -2902,46 +2901,6 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
...
@@ -2902,46 +2901,6 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
expr
->
plan_simple_type
=
exprType
(
tle
->
expr
);
expr
->
plan_simple_type
=
exprType
(
tle
->
expr
);
}
}
/* ----------
* exec_eval_clear_fcache - The function cache is palloc()'d by
* the executor, and contains call specific
* data based on the arguments. This has
* to be recalculated.
* ----------
*/
static
void
exec_eval_clear_fcache
(
Node
*
node
)
{
/* This tree walk requires no special setup, so away we go... */
exec_eval_clear_fcache_walker
(
node
,
NULL
);
}
static
bool
exec_eval_clear_fcache_walker
(
Node
*
node
,
void
*
context
)
{
if
(
node
==
NULL
)
return
false
;
if
(
IsA
(
node
,
Expr
))
{
Expr
*
expr
=
(
Expr
*
)
node
;
switch
(
expr
->
opType
)
{
case
OP_EXPR
:
((
Oper
*
)
(
expr
->
oper
))
->
op_fcache
=
NULL
;
break
;
case
FUNC_EXPR
:
((
Func
*
)
(
expr
->
oper
))
->
func_fcache
=
NULL
;
break
;
default:
break
;
}
}
return
expression_tree_walker
(
node
,
exec_eval_clear_fcache_walker
,
context
);
}
/* ----------
/* ----------
* exec_set_found Set the global found variable
* exec_set_found Set the global found variable
* to true/false
* to true/false
...
...
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