Don't copyObject into the wrong memory context

utilityStmt sometimes (such as when it's inside of a plpgsql function)
comes from a cached plan, which is kept in a child of the
CacheMemoryContext. When we naively call copyObject we're copying it into
a statement-local context, which corrupts the cached plan when it's
thrown away.
pull/2104/head
Brian Cloutier 2018-04-24 19:22:14 -07:00 committed by Brian Cloutier
parent 663c9b2a39
commit f8fb7a27fb
3 changed files with 45 additions and 2 deletions

View File

@ -62,6 +62,7 @@
#include "foreign/foreign.h"
#include "lib/stringinfo.h"
#include "nodes/bitmapset.h"
#include "nodes/memnodes.h"
#include "nodes/nodes.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
@ -311,12 +312,17 @@ multi_ProcessUtility(PlannedStmt *pstmt,
if (IsA(parsetree, CopyStmt))
{
/* copy parse tree since we might scribble on it to fix the schema name */
parsetree = copyObject(parsetree);
MemoryContext planContext = GetMemoryChunkContext(parsetree);
MemoryContext previousContext;
parsetree = copyObject(parsetree);
parsetree = ProcessCopyStmt((CopyStmt *) parsetree, completionTag,
&commandMustRunAsOwner);
previousContext = MemoryContextSwitchTo(planContext);
parsetree = copyObject(parsetree);
MemoryContextSwitchTo(previousContext);
if (parsetree == NULL)
{
return;

View File

@ -1233,9 +1233,31 @@ SELECT copy_in_plpgsql();
(1 row)
-- test prepared COPY on a non-distributed table
CREATE TABLE local_ddl (x int);
CREATE OR REPLACE FUNCTION local_copy_in_plpgsql()
RETURNS VOID AS
$BODY$
BEGIN
COPY local_ddl (x) FROM PROGRAM 'echo 1' WITH CSV;
END;
$BODY$ LANGUAGE plpgsql;
SELECT local_copy_in_plpgsql();
local_copy_in_plpgsql
-----------------------
(1 row)
SELECT local_copy_in_plpgsql();
local_copy_in_plpgsql
-----------------------
(1 row)
DROP FUNCTION ddl_in_plpgsql();
DROP FUNCTION copy_in_plpgsql();
DROP TABLE prepare_ddl;
DROP TABLE local_ddl;
-- clean-up functions
DROP FUNCTION plpgsql_test_1();
DROP FUNCTION plpgsql_test_2();

View File

@ -563,9 +563,24 @@ $BODY$ LANGUAGE plpgsql;
SELECT copy_in_plpgsql();
SELECT copy_in_plpgsql();
-- test prepared COPY on a non-distributed table
CREATE TABLE local_ddl (x int);
CREATE OR REPLACE FUNCTION local_copy_in_plpgsql()
RETURNS VOID AS
$BODY$
BEGIN
COPY local_ddl (x) FROM PROGRAM 'echo 1' WITH CSV;
END;
$BODY$ LANGUAGE plpgsql;
SELECT local_copy_in_plpgsql();
SELECT local_copy_in_plpgsql();
DROP FUNCTION ddl_in_plpgsql();
DROP FUNCTION copy_in_plpgsql();
DROP TABLE prepare_ddl;
DROP TABLE local_ddl;
-- clean-up functions
DROP FUNCTION plpgsql_test_1();