Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

COPY inside plpgsql functions fails after first invocation? #2127

Closed
lithp opened this issue Apr 24, 2018 · 2 comments
Closed

COPY inside plpgsql functions fails after first invocation? #2127

lithp opened this issue Apr 24, 2018 · 2 comments
Labels

Comments

@lithp
Copy link
Contributor

lithp commented Apr 24, 2018

brian=# CREATE FUNCTION doit() RETURNS void AS $$
BEGIN
  COPY (SELECT 'hi') TO '/home/brian/Work/pg-10/some_file';
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
brian=# SELECT doit();
 doit 
------
 
(1 row)

brian=# SELECT doit();
WARNING:  unrecognized node type: 2139062143
ERROR:  unexpected command tag "???"
CONTEXT:  SQL statement "COPY (SELECT 'hi') TO '/home/brian/Work/pg-10/some_file'"
PL/pgSQL function doit() line 3 at SQL statement

Even more tellingly:

brian=# CREATE FUNCTION doit() RETURNS void AS $$
BEGIN
  COPY (SELECT 'hi') TO '/home/brian/Work/pg-10/some_file';
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
brian=# SELECT doit();
 doit 
------
 
(1 row)

brian=# SELECT doit();
 doit 
------
 
(1 row)

brian=# SELECT doit();
 doit 
------
 
(1 row)

brian=# CREATE EXTENSION citus;
CREATE EXTENSION
brian=# SELECT doit();
 doit 
------
 
(1 row)

brian=# SELECT doit();
WARNING:  unrecognized node type: 9
ERROR:  unexpected command tag "???"
CONTEXT:  SQL statement "COPY (SELECT 'hi') TO '/home/brian/Work/pg-10/some_file'"
PL/pgSQL function doit() line 3 at SQL statement
@lithp
Copy link
Contributor Author

lithp commented Apr 25, 2018

This happens because of some code in multi_ProcessUtility which copies parsetree:

if (IsA(parsetree, CopyStmt))
{
	/* copy parse tree since we might scribble on it to fix the schema name */
	parsetree = copyObject(parsetree);

	parsetree = ProcessCopyStmt((CopyStmt *) parsetree, completionTag,
				    &commandMustRunAsOwner);

        ...
}

and then assigns the copy to pstmt->utilityStmt:

pstmt->utilityStmt = parsetree;
standard_ProcessUtility(pstmt, queryString, context,
			params, queryEnv, dest, completionTag);

(this code was added in 853f07d, which fixed COPY in plpgsql for distributed tables, but broke it for local tables.)

The problem is that, when we're inside plpgsql the plan gets cached and reused between statements. It belongs to a memory context which is a child of CacheMemoryContext. When we call copyObject, we create a copy which lives in the local executor context, which is reset at the end of the statement.

@lithp
Copy link
Contributor Author

lithp commented May 15, 2018

Fixed with #2128

@lithp lithp closed this as completed May 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant