Skip to content

Commit 0147b19

Browse files
committed
Fix a many-legged critter reported by chifungfan@yahoo.com: under the
right circumstances a hash join executed as a DECLARE CURSOR/FETCH query would crash the backend. Problem as seen in current sources was that the hash tables were stored in a context that was a child of TransactionCommandContext, which got zapped at completion of the FETCH command --- but cursor cleanup executed at COMMIT expected the tables to still be valid. I haven't chased down the details as seen in 7.0.* but I'm sure it's the same general problem.
1 parent 94e90d9 commit 0147b19

File tree

7 files changed

+84
-51
lines changed

7 files changed

+84
-51
lines changed

src/backend/commands/copy.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.120 2000/08/06 04:26:40 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.121 2000/08/22 04:06:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -29,6 +29,7 @@
2929
#include "executor/executor.h"
3030
#include "libpq/libpq.h"
3131
#include "miscadmin.h"
32+
#include "tcop/pquery.h"
3233
#include "tcop/tcopprot.h"
3334
#include "utils/acl.h"
3435
#include "utils/builtins.h"
@@ -598,7 +599,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
598599
tuples_read = 0;
599600
bool reading_to_eof = true;
600601
RelationInfo *relationInfo;
601-
EState *estate = makeNode(EState); /* for ExecConstraints() */
602+
EState *estate = CreateExecutorState(); /* for ExecConstraints() */
602603
TupleTable tupleTable;
603604
TupleTableSlot *slot;
604605
Oid loaded_oid = InvalidOid;

src/backend/executor/execMain.c

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
*
2828
*
2929
* IDENTIFICATION
30-
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.123 2000/08/06 04:26:26 tgl Exp $
30+
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.124 2000/08/22 04:06:19 tgl Exp $
3131
*
3232
*-------------------------------------------------------------------------
3333
*/
@@ -1574,31 +1574,32 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
15741574
{
15751575
int ncheck = rel->rd_att->constr->num_check;
15761576
ConstrCheck *check = rel->rd_att->constr->check;
1577-
MemoryContext oldContext;
15781577
ExprContext *econtext;
1578+
MemoryContext oldContext;
15791579
List *qual;
15801580
int i;
15811581

15821582
/*
1583-
* Make sure econtext, expressions, etc are placed in appropriate context.
1583+
* We will use the EState's per-tuple context for evaluating constraint
1584+
* expressions. Create it if it's not already there; if it is, reset it
1585+
* to free previously-used storage.
15841586
*/
1585-
oldContext = MemoryContextSwitchTo(TransactionCommandContext);
1586-
1587-
/*
1588-
* Create or reset the exprcontext for evaluating constraint expressions.
1589-
*/
1590-
econtext = estate->es_constraint_exprcontext;
1587+
econtext = estate->es_per_tuple_exprcontext;
15911588
if (econtext == NULL)
1592-
estate->es_constraint_exprcontext = econtext =
1593-
MakeExprContext(NULL, TransactionCommandContext);
1589+
{
1590+
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
1591+
estate->es_per_tuple_exprcontext = econtext =
1592+
MakeExprContext(NULL, estate->es_query_cxt);
1593+
MemoryContextSwitchTo(oldContext);
1594+
}
15941595
else
15951596
ResetExprContext(econtext);
15961597

15971598
/*
15981599
* If first time through for current result relation, set up econtext's
15991600
* range table to refer to result rel, and build expression nodetrees
1600-
* for rel's constraint expressions. All this stuff is kept in
1601-
* TransactionCommandContext so it will still be here next time through.
1601+
* for rel's constraint expressions. All this stuff is kept in the
1602+
* per-query memory context so it will still be here next time through.
16021603
*
16031604
* NOTE: if there are multiple result relations (eg, due to inheritance)
16041605
* then we leak storage for prior rel's expressions and rangetable.
@@ -1608,7 +1609,14 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
16081609
if (econtext->ecxt_range_table == NIL ||
16091610
getrelid(1, econtext->ecxt_range_table) != RelationGetRelid(rel))
16101611
{
1611-
RangeTblEntry *rte = makeNode(RangeTblEntry);
1612+
RangeTblEntry *rte;
1613+
1614+
/*
1615+
* Make sure expressions, etc are placed in appropriate context.
1616+
*/
1617+
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
1618+
1619+
rte = makeNode(RangeTblEntry);
16121620

16131621
rte->relname = RelationGetRelationName(rel);
16141622
rte->ref = makeNode(Attr);
@@ -1627,10 +1635,10 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
16271635
qual = (List *) stringToNode(check[i].ccbin);
16281636
estate->es_result_relation_constraints[i] = qual;
16291637
}
1630-
}
16311638

1632-
/* Done with building long-lived items */
1633-
MemoryContextSwitchTo(oldContext);
1639+
/* Done with building long-lived items */
1640+
MemoryContextSwitchTo(oldContext);
1641+
}
16341642

16351643
/* Arrange for econtext's scan tuple to be the tuple under test */
16361644
econtext->ecxt_scantuple = slot;

src/backend/executor/execUtils.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.64 2000/07/14 22:17:45 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.65 2000/08/22 04:06:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -866,9 +866,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
866866

867867
heapTuple = slot->val;
868868

869-
/* ----------------
870-
* get information from the result relation info structure.
871-
* ----------------
869+
/*
870+
* Get information from the result relation info structure.
872871
*/
873872
resultRelationInfo = estate->es_result_relation_info;
874873
numIndices = resultRelationInfo->ri_NumIndices;
@@ -877,14 +876,26 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
877876
heapRelation = resultRelationInfo->ri_RelationDesc;
878877
heapDescriptor = RelationGetDescr(heapRelation);
879878

880-
/* ----------------
881-
* Make a temporary expr/memory context for evaluating predicates
882-
* and functional-index functions.
883-
* XXX should do this once per command not once per tuple, and
884-
* just reset it once per tuple.
885-
* ----------------
879+
/*
880+
* We will use the EState's per-tuple context for evaluating predicates
881+
* and functional-index functions. Create it if it's not already there;
882+
* if it is, reset it to free previously-used storage.
886883
*/
887-
econtext = MakeExprContext(slot, TransactionCommandContext);
884+
econtext = estate->es_per_tuple_exprcontext;
885+
if (econtext == NULL)
886+
{
887+
MemoryContext oldContext;
888+
889+
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
890+
estate->es_per_tuple_exprcontext = econtext =
891+
MakeExprContext(NULL, estate->es_query_cxt);
892+
MemoryContextSwitchTo(oldContext);
893+
}
894+
else
895+
ResetExprContext(econtext);
896+
897+
/* Arrange for econtext's scan tuple to be the tuple under test */
898+
econtext->ecxt_scantuple = slot;
888899

889900
/* ----------------
890901
* for each index, form and insert the index tuple
@@ -935,8 +946,6 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
935946
if (result)
936947
pfree(result);
937948
}
938-
939-
FreeExprContext(econtext);
940949
}
941950

942951
void

src/backend/executor/nodeHash.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
*
10-
* $Id: nodeHash.c,v 1.50 2000/07/17 03:04:53 tgl Exp $
10+
* $Id: nodeHash.c,v 1.51 2000/08/22 04:06:19 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -334,7 +334,8 @@ ExecHashTableCreate(Hash *node)
334334

335335
/* ----------------
336336
* Initialize the hash table control block.
337-
* The hashtable control block is just palloc'd from executor memory.
337+
* The hashtable control block is just palloc'd from the executor's
338+
* per-query memory context.
338339
* ----------------
339340
*/
340341
hashtable = (HashJoinTable) palloc(sizeof(HashTableData));
@@ -361,7 +362,7 @@ ExecHashTableCreate(Hash *node)
361362
* working storage. See notes in executor/hashjoin.h.
362363
* ----------------
363364
*/
364-
hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
365+
hashtable->hashCxt = AllocSetContextCreate(CurrentMemoryContext,
365366
"HashTableContext",
366367
ALLOCSET_DEFAULT_MINSIZE,
367368
ALLOCSET_DEFAULT_INITSIZE,

src/backend/tcop/pquery.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.37 2000/07/17 03:05:15 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.38 2000/08/22 04:06:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -68,8 +68,8 @@ CreateExecutorState(void)
6868
state->es_direction = ForwardScanDirection;
6969
state->es_range_table = NIL;
7070

71-
state->es_into_relation_descriptor = NULL;
7271
state->es_result_relation_info = NULL;
72+
state->es_into_relation_descriptor = NULL;
7373

7474
state->es_param_list_info = NULL;
7575
state->es_param_exec_vals = NULL;
@@ -78,6 +78,10 @@ CreateExecutorState(void)
7878

7979
state->es_junkFilter = NULL;
8080

81+
state->es_query_cxt = CurrentMemoryContext;
82+
83+
state->es_per_tuple_exprcontext = NULL;
84+
8185
/* ----------------
8286
* return the executor state structure
8387
* ----------------
@@ -144,13 +148,11 @@ PreparePortal(char *portalName)
144148
}
145149

146150
/* ----------------
147-
* Create the new portal and make its memory context active.
151+
* Create the new portal.
148152
* ----------------
149153
*/
150154
portal = CreatePortal(portalName);
151155

152-
MemoryContextSwitchTo(PortalGetHeapMemory(portal));
153-
154156
return portal;
155157
}
156158

@@ -170,8 +172,9 @@ ProcessQuery(Query *parsetree,
170172
char *tag;
171173
bool isRetrieveIntoPortal;
172174
bool isRetrieveIntoRelation;
173-
Portal portal = NULL;
174175
char *intoName = NULL;
176+
Portal portal = NULL;
177+
MemoryContext oldContext = NULL;
175178
QueryDesc *queryDesc;
176179
EState *state;
177180
TupleDesc attinfo;
@@ -217,14 +220,18 @@ ProcessQuery(Query *parsetree,
217220
if (isRetrieveIntoPortal)
218221
{
219222
portal = PreparePortal(intoName);
220-
/* CurrentMemoryContext is now pointing to portal's context */
223+
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
221224
parsetree = copyObject(parsetree);
222225
plan = copyObject(plan);
226+
/*
227+
* We stay in portal's memory context for now, so that query desc,
228+
* EState, and plan startup info are also allocated in the portal
229+
* context.
230+
*/
223231
}
224232

225233
/* ----------------
226-
* Now we can create the QueryDesc object (this is also in
227-
* the portal context, if portal retrieve).
234+
* Now we can create the QueryDesc object.
228235
* ----------------
229236
*/
230237
queryDesc = CreateQueryDesc(parsetree, plan, dest);
@@ -241,7 +248,7 @@ ProcessQuery(Query *parsetree,
241248
queryDesc->dest = (int) None;
242249

243250
/* ----------------
244-
* create a default executor state..
251+
* create a default executor state.
245252
* ----------------
246253
*/
247254
state = CreateExecutorState();
@@ -279,9 +286,11 @@ ProcessQuery(Query *parsetree,
279286
state,
280287
PortalCleanup);
281288

282-
MemoryContextSwitchTo(TransactionCommandContext);
289+
/* Now we can return to caller's memory context. */
290+
MemoryContextSwitchTo(oldContext);
283291

284292
EndCommand(tag, dest);
293+
285294
return;
286295
}
287296

src/include/executor/hashjoin.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: hashjoin.h,v 1.18 2000/07/12 02:37:30 tgl Exp $
10+
* $Id: hashjoin.h,v 1.19 2000/08/22 04:06:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -26,7 +26,7 @@
2626
* This makes it easy and fast to release the storage when we don't need it
2727
* anymore.
2828
*
29-
* The contexts are made children of TransactionCommandContext, ensuring
29+
* The hashtable contexts are made children of the per-query context, ensuring
3030
* that they will be discarded at end of statement even if the join is
3131
* aborted early by an error. (Likewise, any temporary files we make will
3232
* be cleaned up by the virtual file manager in event of an error.)

src/include/nodes/execnodes.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: execnodes.h,v 1.46 2000/08/13 02:50:24 tgl Exp $
10+
* $Id: execnodes.h,v 1.47 2000/08/22 04:06:22 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -223,9 +223,14 @@ typedef struct EState
223223
uint32 es_processed; /* # of tuples processed */
224224
Oid es_lastoid; /* last oid processed (by INSERT) */
225225
List *es_rowMark; /* not good place, but there is no other */
226-
/* these two fields are storage space for ExecConstraints(): */
226+
MemoryContext es_query_cxt; /* per-query context in which EState lives */
227+
/* this ExprContext is for per-output-tuple operations, such as
228+
* constraint checks and index-value computations. It can be reset
229+
* for each output tuple. Note that it will be created only if needed.
230+
*/
231+
ExprContext *es_per_tuple_exprcontext;
232+
/* this field is storage space for ExecConstraints(): */
227233
List **es_result_relation_constraints;
228-
ExprContext *es_constraint_exprcontext;
229234
/* Below is to re-evaluate plan qual in READ COMMITTED mode */
230235
struct Plan *es_origPlan;
231236
Pointer es_evalPlanQual;

0 commit comments

Comments
 (0)