* Transform a FOR [KEY] UPDATE/SHARE clause * * This basically involves replacing names by integer relids. * * NB: if you need to change this, see also markQueryForLocking() * in rewriteHandler.c, and isLockedRefname() in parse_relation.c. */
| 3696 | * in rewriteHandler.c, and isLockedRefname() in parse_relation.c. |
| 3697 | */ |
| 3698 | static void |
| 3699 | transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, |
| 3700 | bool pushedDown) |
| 3701 | { |
| 3702 | List *lockedRels = lc->lockedRels; |
| 3703 | ListCell *l; |
| 3704 | ListCell *rt; |
| 3705 | Index i; |
| 3706 | LockingClause *allrels; |
| 3707 | |
| 3708 | CheckSelectLocking(qry, lc->strength); |
| 3709 | |
| 3710 | /* make a clause we can pass down to subqueries to select all rels */ |
| 3711 | allrels = makeNode(LockingClause); |
| 3712 | allrels->lockedRels = NIL; /* indicates all rels */ |
| 3713 | allrels->strength = lc->strength; |
| 3714 | allrels->waitPolicy = lc->waitPolicy; |
| 3715 | |
| 3716 | if (lockedRels == NIL) |
| 3717 | { |
| 3718 | /* |
| 3719 | * Lock all regular tables used in query and its subqueries. We |
| 3720 | * examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD |
| 3721 | * in rules. This is a bit of an abuse of a mostly-obsolete flag, but |
| 3722 | * it's convenient. We can't rely on the namespace mechanism that has |
| 3723 | * largely replaced inFromCl, since for example we need to lock |
| 3724 | * base-relation RTEs even if they are masked by upper joins. |
| 3725 | */ |
| 3726 | i = 0; |
| 3727 | foreach(rt, qry->rtable) |
| 3728 | { |
| 3729 | RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); |
| 3730 | |
| 3731 | ++i; |
| 3732 | if (!rte->inFromCl) |
| 3733 | continue; |
| 3734 | switch (rte->rtekind) |
| 3735 | { |
| 3736 | case RTE_RELATION: |
| 3737 | if (rel_is_external_table(rte->relid)) |
| 3738 | ereport(ERROR, |
| 3739 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 3740 | errmsg("SELECT FOR UPDATE/SHARE cannot be applied to external tables"))); |
| 3741 | |
| 3742 | applyLockingClause(qry, i, lc->strength, lc->waitPolicy, |
| 3743 | pushedDown); |
| 3744 | rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; |
| 3745 | break; |
| 3746 | case RTE_SUBQUERY: |
| 3747 | applyLockingClause(qry, i, lc->strength, lc->waitPolicy, |
| 3748 | pushedDown); |
| 3749 | |
| 3750 | /* |
| 3751 | * FOR UPDATE/SHARE of subquery is propagated to all of |
| 3752 | * subquery's rels, too. We could do this later (based on |
| 3753 | * the marking of the subquery RTE) but it is convenient |
| 3754 | * to have local knowledge in each query level about which |
| 3755 | * rels need to be opened with RowShareLock. |
no test coverage detected