aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r--src/backend/commands/copy.c48
1 files changed, 37 insertions, 11 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 83e8f891222..08abe141f41 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -282,12 +282,13 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
/* non-export function prototypes */
static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query,
- const char *queryString, List *attnamelist, List *options);
+ const char *queryString, const Oid queryRelId, List *attnamelist,
+ List *options);
static void EndCopy(CopyState cstate);
static void ClosePipeToProgram(CopyState cstate);
static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString,
- const char *filename, bool is_program, List *attnamelist,
- List *options);
+ const Oid queryRelId, const char *filename, bool is_program,
+ List *attnamelist, List *options);
static void EndCopyTo(CopyState cstate);
static uint64 DoCopyTo(CopyState cstate);
static uint64 CopyTo(CopyState cstate);
@@ -843,7 +844,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
ExecCheckRTPerms(list_make1(rte), true);
/*
- * Permission check for row security.
+ * Permission check for row security policies.
*
* check_enable_rls will ereport(ERROR) if the user has requested
* something invalid and will otherwise indicate if we should enable
@@ -866,7 +867,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
if (is_from)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("COPY FROM not supported with row security."),
+ errmsg("COPY FROM not supported with row level security."),
errhint("Use direct INSERT statements instead.")));
/* Build target list */
@@ -886,7 +887,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
target->location = 1;
/* Build FROM clause */
- from = makeRangeVar(NULL, RelationGetRelationName(rel), 1);
+ from = stmt->relation;
/* Build query */
select = makeNode(SelectStmt);
@@ -895,8 +896,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
query = (Node*) select;
- relid = InvalidOid;
-
/* Close the handle to the relation as it is no longer needed. */
heap_close(rel, (is_from ? RowExclusiveLock : AccessShareLock));
rel = NULL;
@@ -926,7 +925,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
}
else
{
- cstate = BeginCopyTo(rel, query, queryString,
+ cstate = BeginCopyTo(rel, query, queryString, relid,
stmt->filename, stmt->is_program,
stmt->attlist, stmt->options);
*processed = DoCopyTo(cstate); /* copy from database to file */
@@ -1304,6 +1303,7 @@ BeginCopy(bool is_from,
Relation rel,
Node *raw_query,
const char *queryString,
+ const Oid queryRelId,
List *attnamelist,
List *options)
{
@@ -1395,6 +1395,30 @@ BeginCopy(bool is_from,
plan = planner(query, 0, NULL);
/*
+ * If we were passed in a relid, make sure we got the same one back
+ * after planning out the query. It's possible that it changed between
+ * when we checked the policies on the table and decided to use a query
+ * and now.
+ */
+ if (queryRelId != InvalidOid)
+ {
+ Oid relid = linitial_oid(plan->relationOids);
+
+ /*
+ * There should only be one relationOid in this case, since we will
+ * only get here when we have changed the command for the user from
+ * a "COPY relation TO" to "COPY (SELECT * FROM relation) TO", to
+ * allow row level security policies to be applied.
+ */
+ Assert(list_length(plan->relationOids) == 1);
+
+ if (relid != queryRelId)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("relation referenced by COPY statement has changed")));
+ }
+
+ /*
* Use a snapshot with an updated command ID to ensure this query sees
* results of any previously executed queries.
*/
@@ -1595,6 +1619,7 @@ static CopyState
BeginCopyTo(Relation rel,
Node *query,
const char *queryString,
+ const Oid queryRelId,
const char *filename,
bool is_program,
List *attnamelist,
@@ -1636,7 +1661,8 @@ BeginCopyTo(Relation rel,
RelationGetRelationName(rel))));
}
- cstate = BeginCopy(false, rel, query, queryString, attnamelist, options);
+ cstate = BeginCopy(false, rel, query, queryString, queryRelId, attnamelist,
+ options);
oldcontext = MemoryContextSwitchTo(cstate->copycontext);
if (pipe)
@@ -2565,7 +2591,7 @@ BeginCopyFrom(Relation rel,
MemoryContext oldcontext;
bool volatile_defexprs;
- cstate = BeginCopy(true, rel, NULL, NULL, attnamelist, options);
+ cstate = BeginCopy(true, rel, NULL, NULL, InvalidOid, attnamelist, options);
oldcontext = MemoryContextSwitchTo(cstate->copycontext);
/* Initialize state variables */