* Check that the query does not imply any writes to non-temp tables; * unless we're in parallel mode, in which case don't even allow writes * to temp tables. * * This function is used to check if the current statement will perform any writes. * It is used to enforce: * (1) read-only mode (both fts and transaction isolation level read only) * as well as * (2) to keep track of when a
| 1655 | * ensures that we use two-phase commit for this transaction. |
| 1656 | */ |
| 1657 | static void |
| 1658 | ExecCheckXactReadOnly(PlannedStmt *plannedstmt) |
| 1659 | { |
| 1660 | ListCell *l; |
| 1661 | int rti; |
| 1662 | |
| 1663 | /* |
| 1664 | * CREATE TABLE AS or SELECT INTO? |
| 1665 | * |
| 1666 | * XXX should we allow this if the destination is temp? Considering that |
| 1667 | * it would still require catalog changes, probably not. |
| 1668 | */ |
| 1669 | if (plannedstmt->intoClause != NULL) |
| 1670 | { |
| 1671 | if ((plannedstmt->intoClause->rel && plannedstmt->intoClause->rel->relpersistence == RELPERSISTENCE_TEMP) |
| 1672 | || (plannedstmt->intoClause->rel == NULL && plannedstmt->intoClause->ivm)) |
| 1673 | ExecutorMarkTransactionDoesWrites(); |
| 1674 | else |
| 1675 | PreventCommandIfReadOnly(CreateCommandName((Node *) plannedstmt)); |
| 1676 | } |
| 1677 | |
| 1678 | /* |
| 1679 | * Refresh matview will write xlog. |
| 1680 | */ |
| 1681 | if (plannedstmt->refreshClause != NULL) |
| 1682 | { |
| 1683 | PreventCommandIfReadOnly(CreateCommandName((Node *) plannedstmt)); |
| 1684 | } |
| 1685 | |
| 1686 | rti = 0; |
| 1687 | /* |
| 1688 | * Fail if write permissions are requested in parallel mode for table |
| 1689 | * (temp or non-temp), otherwise fail for any non-temp table. |
| 1690 | */ |
| 1691 | foreach(l, plannedstmt->rtable) |
| 1692 | { |
| 1693 | RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); |
| 1694 | |
| 1695 | rti++; |
| 1696 | |
| 1697 | if (rte->rtekind != RTE_RELATION) |
| 1698 | continue; |
| 1699 | |
| 1700 | if ((rte->requiredPerms & (~ACL_SELECT)) == 0) |
| 1701 | continue; |
| 1702 | |
| 1703 | /* |
| 1704 | * External and foreign tables don't need two phase commit which is for |
| 1705 | * local mpp tables |
| 1706 | */ |
| 1707 | if (get_rel_relkind(rte->relid) == RELKIND_FOREIGN_TABLE) |
| 1708 | continue; |
| 1709 | |
| 1710 | if (isTempNamespace(get_rel_namespace(rte->relid))) |
| 1711 | { |
| 1712 | ExecutorMarkTransactionDoesWrites(); |
| 1713 | continue; |
| 1714 | } |
no test coverage detected