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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy