mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
Allow foreign tables to participate in inheritance.
Foreign tables can now be inheritance children, or parents. Much of the system was already ready for this, but we had to fix a few things of course, mostly in the area of planner and executor handling of row locks. As side effects of this, allow foreign tables to have NOT VALID CHECK constraints (and hence to accept ALTER ... VALIDATE CONSTRAINT), and to accept ALTER SET STORAGE and ALTER SET WITH/WITHOUT OIDS. Continuing to disallow these things would've required bizarre and inconsistent special cases in inheritance behavior. Since foreign tables don't enforce CHECK constraints anyway, a NOT VALID one is a complete no-op, but that doesn't mean we shouldn't allow it. And it's possible that some FDWs might have use for SET STORAGE or SET WITH OIDS, though doubtless they will be no-ops for most. An additional change in support of this is that when a ModifyTable node has multiple target tables, they will all now be explicitly identified in EXPLAIN output, for example: Update on pt1 (cost=0.00..321.05 rows=3541 width=46) Update on pt1 Foreign Update on ft1 Foreign Update on ft2 Update on child3 -> Seq Scan on pt1 (cost=0.00..0.00 rows=1 width=46) -> Foreign Scan on ft1 (cost=100.00..148.03 rows=1170 width=46) -> Foreign Scan on ft2 (cost=100.00..148.03 rows=1170 width=46) -> Seq Scan on child3 (cost=0.00..25.00 rows=1200 width=46) This was done mainly to provide an unambiguous place to attach "Remote SQL" fields, but it is useful for inherited updates even when no foreign tables are involved. Shigeru Hanada and Etsuro Fujita, reviewed by Ashutosh Bapat and Kyotaro Horiguchi, some additional hacking by me
This commit is contained in:
@ -2224,35 +2224,7 @@ preprocess_rowmarks(PlannerInfo *root)
|
||||
newrc = makeNode(PlanRowMark);
|
||||
newrc->rti = newrc->prti = rc->rti;
|
||||
newrc->rowmarkId = ++(root->glob->lastRowMarkId);
|
||||
if (rte->relkind == RELKIND_FOREIGN_TABLE)
|
||||
{
|
||||
/* For now, we force all foreign tables to use ROW_MARK_COPY */
|
||||
newrc->markType = ROW_MARK_COPY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular table, apply the appropriate lock type */
|
||||
switch (rc->strength)
|
||||
{
|
||||
case LCS_NONE:
|
||||
/* we intentionally throw an error for LCS_NONE */
|
||||
elog(ERROR, "unrecognized LockClauseStrength %d",
|
||||
(int) rc->strength);
|
||||
break;
|
||||
case LCS_FORKEYSHARE:
|
||||
newrc->markType = ROW_MARK_KEYSHARE;
|
||||
break;
|
||||
case LCS_FORSHARE:
|
||||
newrc->markType = ROW_MARK_SHARE;
|
||||
break;
|
||||
case LCS_FORNOKEYUPDATE:
|
||||
newrc->markType = ROW_MARK_NOKEYEXCLUSIVE;
|
||||
break;
|
||||
case LCS_FORUPDATE:
|
||||
newrc->markType = ROW_MARK_EXCLUSIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newrc->markType = select_rowmark_type(rte, rc->strength);
|
||||
newrc->allMarkTypes = (1 << newrc->markType);
|
||||
newrc->strength = rc->strength;
|
||||
newrc->waitPolicy = rc->waitPolicy;
|
||||
@ -2277,12 +2249,7 @@ preprocess_rowmarks(PlannerInfo *root)
|
||||
newrc = makeNode(PlanRowMark);
|
||||
newrc->rti = newrc->prti = i;
|
||||
newrc->rowmarkId = ++(root->glob->lastRowMarkId);
|
||||
/* real tables support REFERENCE, anything else needs COPY */
|
||||
if (rte->rtekind == RTE_RELATION &&
|
||||
rte->relkind != RELKIND_FOREIGN_TABLE)
|
||||
newrc->markType = ROW_MARK_REFERENCE;
|
||||
else
|
||||
newrc->markType = ROW_MARK_COPY;
|
||||
newrc->markType = select_rowmark_type(rte, LCS_NONE);
|
||||
newrc->allMarkTypes = (1 << newrc->markType);
|
||||
newrc->strength = LCS_NONE;
|
||||
newrc->waitPolicy = LockWaitBlock; /* doesn't matter */
|
||||
@ -2294,6 +2261,49 @@ preprocess_rowmarks(PlannerInfo *root)
|
||||
root->rowMarks = prowmarks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select RowMarkType to use for a given table
|
||||
*/
|
||||
RowMarkType
|
||||
select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
|
||||
{
|
||||
if (rte->rtekind != RTE_RELATION)
|
||||
{
|
||||
/* If it's not a table at all, use ROW_MARK_COPY */
|
||||
return ROW_MARK_COPY;
|
||||
}
|
||||
else if (rte->relkind == RELKIND_FOREIGN_TABLE)
|
||||
{
|
||||
/* For now, we force all foreign tables to use ROW_MARK_COPY */
|
||||
return ROW_MARK_COPY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Regular table, apply the appropriate lock type */
|
||||
switch (strength)
|
||||
{
|
||||
case LCS_NONE:
|
||||
/* don't need tuple lock, only ability to re-fetch the row */
|
||||
return ROW_MARK_REFERENCE;
|
||||
break;
|
||||
case LCS_FORKEYSHARE:
|
||||
return ROW_MARK_KEYSHARE;
|
||||
break;
|
||||
case LCS_FORSHARE:
|
||||
return ROW_MARK_SHARE;
|
||||
break;
|
||||
case LCS_FORNOKEYUPDATE:
|
||||
return ROW_MARK_NOKEYEXCLUSIVE;
|
||||
break;
|
||||
case LCS_FORUPDATE:
|
||||
return ROW_MARK_EXCLUSIVE;
|
||||
break;
|
||||
}
|
||||
elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
|
||||
return ROW_MARK_EXCLUSIVE; /* keep compiler quiet */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* preprocess_limit - do pre-estimation for LIMIT and/or OFFSET clauses
|
||||
*
|
||||
|
@ -1337,12 +1337,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
|
||||
|
||||
/*
|
||||
* Build an RTE for the child, and attach to query's rangetable list.
|
||||
* We copy most fields of the parent's RTE, but replace relation OID,
|
||||
* and set inh = false. Also, set requiredPerms to zero since all
|
||||
* required permissions checks are done on the original RTE.
|
||||
* We copy most fields of the parent's RTE, but replace relation OID
|
||||
* and relkind, and set inh = false. Also, set requiredPerms to zero
|
||||
* since all required permissions checks are done on the original RTE.
|
||||
*/
|
||||
childrte = copyObject(rte);
|
||||
childrte->relid = childOID;
|
||||
childrte->relkind = newrelation->rd_rel->relkind;
|
||||
childrte->inh = false;
|
||||
childrte->requiredPerms = 0;
|
||||
parse->rtable = lappend(parse->rtable, childrte);
|
||||
@ -1388,7 +1389,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
|
||||
newrc->rti = childRTindex;
|
||||
newrc->prti = rti;
|
||||
newrc->rowmarkId = oldrc->rowmarkId;
|
||||
newrc->markType = oldrc->markType;
|
||||
/* Reselect rowmark type, because relkind might not match parent */
|
||||
newrc->markType = select_rowmark_type(childrte, oldrc->strength);
|
||||
newrc->allMarkTypes = (1 << newrc->markType);
|
||||
newrc->strength = oldrc->strength;
|
||||
newrc->waitPolicy = oldrc->waitPolicy;
|
||||
|
Reference in New Issue
Block a user