mirror of
https://github.com/postgres/postgres.git
synced 2025-09-05 02:22:28 +03:00
@@ -1377,57 +1377,6 @@ rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rewriteTargetListMerge(Query *parsetree, Relation target_relation)
|
||||
{
|
||||
Var *var = NULL;
|
||||
const char *attrname;
|
||||
TargetEntry *tle;
|
||||
|
||||
Assert(target_relation->rd_rel->relkind == RELKIND_RELATION ||
|
||||
target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
|
||||
target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
|
||||
|
||||
/*
|
||||
* Emit CTID so that executor can find the row to update or delete.
|
||||
*/
|
||||
var = makeVar(parsetree->mergeTarget_relation,
|
||||
SelfItemPointerAttributeNumber,
|
||||
TIDOID,
|
||||
-1,
|
||||
InvalidOid,
|
||||
0);
|
||||
|
||||
attrname = "ctid";
|
||||
tle = makeTargetEntry((Expr *) var,
|
||||
list_length(parsetree->targetList) + 1,
|
||||
pstrdup(attrname),
|
||||
true);
|
||||
|
||||
parsetree->targetList = lappend(parsetree->targetList, tle);
|
||||
|
||||
/*
|
||||
* If we are dealing with partitioned table, then emit TABLEOID so that
|
||||
* executor can find the partition the row belongs to.
|
||||
*/
|
||||
if (target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
||||
{
|
||||
var = makeVar(parsetree->mergeTarget_relation,
|
||||
TableOidAttributeNumber,
|
||||
OIDOID,
|
||||
-1,
|
||||
InvalidOid,
|
||||
0);
|
||||
|
||||
attrname = "tableoid";
|
||||
tle = makeTargetEntry((Expr *) var,
|
||||
list_length(parsetree->targetList) + 1,
|
||||
pstrdup(attrname),
|
||||
true);
|
||||
|
||||
parsetree->targetList = lappend(parsetree->targetList, tle);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* matchLocks -
|
||||
@@ -3382,7 +3331,6 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
|
||||
}
|
||||
else if (event == CMD_UPDATE)
|
||||
{
|
||||
Assert(parsetree->override == OVERRIDING_NOT_SET);
|
||||
parsetree->targetList =
|
||||
rewriteTargetListIU(parsetree->targetList,
|
||||
parsetree->commandType,
|
||||
@@ -3390,50 +3338,6 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
|
||||
rt_entry_relation,
|
||||
parsetree->resultRelation, NULL);
|
||||
}
|
||||
else if (event == CMD_MERGE)
|
||||
{
|
||||
Assert(parsetree->override == OVERRIDING_NOT_SET);
|
||||
|
||||
/*
|
||||
* Rewrite each action targetlist separately
|
||||
*/
|
||||
foreach(lc1, parsetree->mergeActionList)
|
||||
{
|
||||
MergeAction *action = (MergeAction *) lfirst(lc1);
|
||||
|
||||
switch (action->commandType)
|
||||
{
|
||||
case CMD_NOTHING:
|
||||
case CMD_DELETE: /* Nothing to do here */
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
action->targetList =
|
||||
rewriteTargetListIU(action->targetList,
|
||||
action->commandType,
|
||||
parsetree->override,
|
||||
rt_entry_relation,
|
||||
parsetree->resultRelation,
|
||||
NULL);
|
||||
break;
|
||||
case CMD_INSERT:
|
||||
{
|
||||
InsertStmt *istmt = (InsertStmt *) action->stmt;
|
||||
|
||||
action->targetList =
|
||||
rewriteTargetListIU(action->targetList,
|
||||
action->commandType,
|
||||
istmt->override,
|
||||
rt_entry_relation,
|
||||
parsetree->resultRelation,
|
||||
NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized commandType: %d", action->commandType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event == CMD_DELETE)
|
||||
{
|
||||
/* Nothing to do here */
|
||||
@@ -3447,20 +3351,13 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
|
||||
locks = matchLocks(event, rt_entry_relation->rd_rules,
|
||||
result_relation, parsetree, &hasUpdate);
|
||||
|
||||
/*
|
||||
* XXX MERGE doesn't support write rules because they would violate
|
||||
* the SQL Standard spec and would be unclear how they should work.
|
||||
*/
|
||||
if (event == CMD_MERGE)
|
||||
product_queries = NIL;
|
||||
else
|
||||
product_queries = fireRules(parsetree,
|
||||
result_relation,
|
||||
event,
|
||||
locks,
|
||||
&instead,
|
||||
&returning,
|
||||
&qual_product);
|
||||
product_queries = fireRules(parsetree,
|
||||
result_relation,
|
||||
event,
|
||||
locks,
|
||||
&instead,
|
||||
&returning,
|
||||
&qual_product);
|
||||
|
||||
/*
|
||||
* If there were no INSTEAD rules, and the target relation is a view
|
||||
|
@@ -379,95 +379,6 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FOR MERGE, we fetch policies for UPDATE, DELETE and INSERT (and ALL)
|
||||
* and set them up so that we can enforce the appropriate policy depending
|
||||
* on the final action we take.
|
||||
*
|
||||
* We don't fetch the SELECT policies since they are correctly applied to
|
||||
* the root->mergeTarget_relation. The target rows are selected after
|
||||
* joining the mergeTarget_relation and the source relation and hence it's
|
||||
* enough to apply SELECT policies to the mergeTarget_relation.
|
||||
*
|
||||
* We don't push the UPDATE/DELETE USING quals to the RTE because we don't
|
||||
* really want to apply them while scanning the relation since we don't
|
||||
* know whether we will be doing a UPDATE or a DELETE at the end. We apply
|
||||
* the respective policy once we decide the final action on the target
|
||||
* tuple.
|
||||
*
|
||||
* XXX We are setting up USING quals as WITH CHECK. If RLS prohibits
|
||||
* UPDATE/DELETE on the target row, we shall throw an error instead of
|
||||
* silently ignoring the row. This is different than how normal
|
||||
* UPDATE/DELETE works and more in line with INSERT ON CONFLICT DO UPDATE
|
||||
* handling.
|
||||
*/
|
||||
if (commandType == CMD_MERGE)
|
||||
{
|
||||
List *merge_permissive_policies;
|
||||
List *merge_restrictive_policies;
|
||||
|
||||
/*
|
||||
* Fetch the UPDATE policies and set them up to execute on the
|
||||
* existing target row before doing UPDATE.
|
||||
*/
|
||||
get_policies_for_relation(rel, CMD_UPDATE, user_id,
|
||||
&merge_permissive_policies,
|
||||
&merge_restrictive_policies);
|
||||
|
||||
/*
|
||||
* WCO_RLS_MERGE_UPDATE_CHECK is used to check UPDATE USING quals on
|
||||
* the existing target row.
|
||||
*/
|
||||
add_with_check_options(rel, rt_index,
|
||||
WCO_RLS_MERGE_UPDATE_CHECK,
|
||||
merge_permissive_policies,
|
||||
merge_restrictive_policies,
|
||||
withCheckOptions,
|
||||
hasSubLinks,
|
||||
true);
|
||||
|
||||
/*
|
||||
* Same with DELETE policies.
|
||||
*/
|
||||
get_policies_for_relation(rel, CMD_DELETE, user_id,
|
||||
&merge_permissive_policies,
|
||||
&merge_restrictive_policies);
|
||||
|
||||
add_with_check_options(rel, rt_index,
|
||||
WCO_RLS_MERGE_DELETE_CHECK,
|
||||
merge_permissive_policies,
|
||||
merge_restrictive_policies,
|
||||
withCheckOptions,
|
||||
hasSubLinks,
|
||||
true);
|
||||
|
||||
/*
|
||||
* No special handling is required for INSERT policies. They will be
|
||||
* checked and enforced during ExecInsert(). But we must add them to
|
||||
* withCheckOptions.
|
||||
*/
|
||||
get_policies_for_relation(rel, CMD_INSERT, user_id,
|
||||
&merge_permissive_policies,
|
||||
&merge_restrictive_policies);
|
||||
|
||||
add_with_check_options(rel, rt_index,
|
||||
WCO_RLS_INSERT_CHECK,
|
||||
merge_permissive_policies,
|
||||
merge_restrictive_policies,
|
||||
withCheckOptions,
|
||||
hasSubLinks,
|
||||
false);
|
||||
|
||||
/* Enforce the WITH CHECK clauses of the UPDATE policies */
|
||||
add_with_check_options(rel, rt_index,
|
||||
WCO_RLS_UPDATE_CHECK,
|
||||
merge_permissive_policies,
|
||||
merge_restrictive_policies,
|
||||
withCheckOptions,
|
||||
hasSubLinks,
|
||||
false);
|
||||
}
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
@@ -527,14 +438,6 @@ get_policies_for_relation(Relation relation, CmdType cmd, Oid user_id,
|
||||
if (policy->polcmd == ACL_DELETE_CHR)
|
||||
cmd_matches = true;
|
||||
break;
|
||||
case CMD_MERGE:
|
||||
|
||||
/*
|
||||
* We do not support a separate policy for MERGE command.
|
||||
* Instead it derives from the policies defined for other
|
||||
* commands.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized policy command type %d",
|
||||
(int) cmd);
|
||||
|
Reference in New Issue
Block a user