|
33 | 33 | #include"access/heapam.h"
|
34 | 34 | #include"access/htup_details.h"
|
35 | 35 | #include"access/sysattr.h"
|
| 36 | +#include"catalog/partition.h" |
36 | 37 | #include"catalog/pg_inherits_fn.h"
|
37 | 38 | #include"catalog/pg_type.h"
|
38 | 39 | #include"miscadmin.h"
|
@@ -100,6 +101,19 @@ static List *generate_append_tlist(List *colTypes, List *colCollations,
|
100 | 101 | staticList*generate_setop_grouplist(SetOperationStmt*op,List*targetlist);
|
101 | 102 | staticvoidexpand_inherited_rtentry(PlannerInfo*root,RangeTblEntry*rte,
|
102 | 103 | Indexrti);
|
| 104 | +staticvoidexpand_partitioned_rtentry(PlannerInfo*root, |
| 105 | +RangeTblEntry*parentrte, |
| 106 | +IndexparentRTindex,Relationparentrel, |
| 107 | +PlanRowMark*parentrc,PartitionDescpartdesc, |
| 108 | +LOCKMODElockmode, |
| 109 | +bool*has_child,List**appinfos, |
| 110 | +List**partitioned_child_rels); |
| 111 | +staticvoidexpand_single_inheritance_child(PlannerInfo*root, |
| 112 | +RangeTblEntry*parentrte, |
| 113 | +IndexparentRTindex,Relationparentrel, |
| 114 | +PlanRowMark*parentrc,Relationchildrel, |
| 115 | +bool*has_child,List**appinfos, |
| 116 | +List**partitioned_child_rels); |
103 | 117 | staticvoidmake_inh_translation_list(Relationoldrelation,
|
104 | 118 | Relationnewrelation,
|
105 | 119 | Indexnewvarno,
|
@@ -1455,131 +1469,62 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
|
1455 | 1469 | /* Scan the inheritance set and expand it */
|
1456 | 1470 | appinfos=NIL;
|
1457 | 1471 | has_child= false;
|
1458 |
| -foreach(l,inhOIDs) |
| 1472 | +if (RelationGetPartitionDesc(oldrelation)!=NULL) |
1459 | 1473 | {
|
1460 |
| -OidchildOID=lfirst_oid(l); |
1461 |
| -Relationnewrelation; |
1462 |
| -RangeTblEntry*childrte; |
1463 |
| -IndexchildRTindex; |
1464 |
| -AppendRelInfo*appinfo; |
1465 |
| - |
1466 |
| -/* Open rel if needed; we already have required locks */ |
1467 |
| -if (childOID!=parentOID) |
1468 |
| -newrelation=heap_open(childOID,NoLock); |
1469 |
| -else |
1470 |
| -newrelation=oldrelation; |
1471 |
| - |
1472 |
| -/* |
1473 |
| - * It is possible that the parent table has children that are temp |
1474 |
| - * tables of other backends. We cannot safely access such tables |
1475 |
| - * (because of buffering issues), and the best thing to do seems to be |
1476 |
| - * to silently ignore them. |
1477 |
| - */ |
1478 |
| -if (childOID!=parentOID&&RELATION_IS_OTHER_TEMP(newrelation)) |
1479 |
| -{ |
1480 |
| -heap_close(newrelation,lockmode); |
1481 |
| -continue; |
1482 |
| -} |
1483 |
| - |
1484 | 1474 | /*
|
1485 |
| - * Build an RTE for the child, and attach to query's rangetable list. |
1486 |
| - * We copy most fields of the parent's RTE, but replace relation OID |
1487 |
| - * and relkind, and set inh = false. Also, set requiredPerms to zero |
1488 |
| - * since all required permissions checks are done on the original RTE. |
1489 |
| - * Likewise, set the child's securityQuals to empty, because we only |
1490 |
| - * want to apply the parent's RLS conditions regardless of what RLS |
1491 |
| - * properties individual children may have. (This is an intentional |
1492 |
| - * choice to make inherited RLS work like regular permissions checks.) |
1493 |
| - * The parent securityQuals will be propagated to children along with |
1494 |
| - * other base restriction clauses, so we don't need to do it here. |
| 1475 | + * If this table has partitions, recursively expand them in the order |
| 1476 | + * in which they appear in the PartitionDesc. But first, expand the |
| 1477 | + * parent itself. |
1495 | 1478 | */
|
1496 |
| -childrte=copyObject(rte); |
1497 |
| -childrte->relid=childOID; |
1498 |
| -childrte->relkind=newrelation->rd_rel->relkind; |
1499 |
| -childrte->inh= false; |
1500 |
| -childrte->requiredPerms=0; |
1501 |
| -childrte->securityQuals=NIL; |
1502 |
| -parse->rtable=lappend(parse->rtable,childrte); |
1503 |
| -childRTindex=list_length(parse->rtable); |
1504 |
| - |
| 1479 | +expand_single_inheritance_child(root,rte,rti,oldrelation,oldrc, |
| 1480 | +oldrelation, |
| 1481 | +&has_child,&appinfos, |
| 1482 | +&partitioned_child_rels); |
| 1483 | +expand_partitioned_rtentry(root,rte,rti,oldrelation,oldrc, |
| 1484 | +RelationGetPartitionDesc(oldrelation), |
| 1485 | +lockmode, |
| 1486 | +&has_child,&appinfos, |
| 1487 | +&partitioned_child_rels); |
| 1488 | +} |
| 1489 | +else |
| 1490 | +{ |
1505 | 1491 | /*
|
1506 |
| - * Build an AppendRelInfo for this parent and child, unless the child |
1507 |
| - * is a partitioned table. |
| 1492 | + * This table has no partitions. Expand any plain inheritance |
| 1493 | + * children in the order the OIDs were returned by |
| 1494 | + * find_all_inheritors. |
1508 | 1495 | */
|
1509 |
| -if (childrte->relkind!=RELKIND_PARTITIONED_TABLE) |
| 1496 | +foreach(l,inhOIDs) |
1510 | 1497 | {
|
1511 |
| -/* Remember if we saw a real child. */ |
| 1498 | +OidchildOID=lfirst_oid(l); |
| 1499 | +Relationnewrelation; |
| 1500 | + |
| 1501 | +/* Open rel if needed; we already have required locks */ |
1512 | 1502 | if (childOID!=parentOID)
|
1513 |
| -has_child= true; |
1514 |
| - |
1515 |
| -appinfo=makeNode(AppendRelInfo); |
1516 |
| -appinfo->parent_relid=rti; |
1517 |
| -appinfo->child_relid=childRTindex; |
1518 |
| -appinfo->parent_reltype=oldrelation->rd_rel->reltype; |
1519 |
| -appinfo->child_reltype=newrelation->rd_rel->reltype; |
1520 |
| -make_inh_translation_list(oldrelation,newrelation,childRTindex, |
1521 |
| -&appinfo->translated_vars); |
1522 |
| -appinfo->parent_reloid=parentOID; |
1523 |
| -appinfos=lappend(appinfos,appinfo); |
| 1503 | +newrelation=heap_open(childOID,NoLock); |
| 1504 | +else |
| 1505 | +newrelation=oldrelation; |
1524 | 1506 |
|
1525 | 1507 | /*
|
1526 |
| - * Translate the column permissions bitmaps to the child's attnums |
1527 |
| - * (we have to build the translated_vars list before we can do |
1528 |
| - * this). But if this is the parent table, leave copyObject's |
1529 |
| - * result alone. |
1530 |
| - * |
1531 |
| - * Note: we need to do this even though the executor won't run any |
1532 |
| - * permissions checks on the child RTE. The |
1533 |
| - * insertedCols/updatedCols bitmaps may be examined for |
1534 |
| - * trigger-firing purposes. |
| 1508 | + * It is possible that the parent table has children that are temp |
| 1509 | + * tables of other backends. We cannot safely access such tables |
| 1510 | + * (because of buffering issues), and the best thing to do seems |
| 1511 | + * to be to silently ignore them. |
1535 | 1512 | */
|
1536 |
| -if (childOID!=parentOID) |
| 1513 | +if (childOID!=parentOID&&RELATION_IS_OTHER_TEMP(newrelation)) |
1537 | 1514 | {
|
1538 |
| -childrte->selectedCols=translate_col_privs(rte->selectedCols, |
1539 |
| -appinfo->translated_vars); |
1540 |
| -childrte->insertedCols=translate_col_privs(rte->insertedCols, |
1541 |
| -appinfo->translated_vars); |
1542 |
| -childrte->updatedCols=translate_col_privs(rte->updatedCols, |
1543 |
| -appinfo->translated_vars); |
| 1515 | +heap_close(newrelation,lockmode); |
| 1516 | +continue; |
1544 | 1517 | }
|
1545 |
| -} |
1546 |
| -else |
1547 |
| -partitioned_child_rels=lappend_int(partitioned_child_rels, |
1548 |
| -childRTindex); |
1549 | 1518 |
|
1550 |
| -/* |
1551 |
| - * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE. |
1552 |
| - */ |
1553 |
| -if (oldrc) |
1554 |
| -{ |
1555 |
| -PlanRowMark*newrc=makeNode(PlanRowMark); |
1556 |
| - |
1557 |
| -newrc->rti=childRTindex; |
1558 |
| -newrc->prti=rti; |
1559 |
| -newrc->rowmarkId=oldrc->rowmarkId; |
1560 |
| -/* Reselect rowmark type, because relkind might not match parent */ |
1561 |
| -newrc->markType=select_rowmark_type(childrte,oldrc->strength); |
1562 |
| -newrc->allMarkTypes= (1 <<newrc->markType); |
1563 |
| -newrc->strength=oldrc->strength; |
1564 |
| -newrc->waitPolicy=oldrc->waitPolicy; |
1565 |
| - |
1566 |
| -/* |
1567 |
| - * We mark RowMarks for partitioned child tables as parent |
1568 |
| - * RowMarks so that the executor ignores them (except their |
1569 |
| - * existence means that the child tables be locked using |
1570 |
| - * appropriate mode). |
1571 |
| - */ |
1572 |
| -newrc->isParent= (childrte->relkind==RELKIND_PARTITIONED_TABLE); |
1573 |
| - |
1574 |
| -/* Include child's rowmark type in parent's allMarkTypes */ |
1575 |
| -oldrc->allMarkTypes |=newrc->allMarkTypes; |
| 1519 | +expand_single_inheritance_child(root,rte,rti,oldrelation,oldrc, |
| 1520 | +newrelation, |
| 1521 | +&has_child,&appinfos, |
| 1522 | +&partitioned_child_rels); |
1576 | 1523 |
|
1577 |
| -root->rowMarks=lappend(root->rowMarks,newrc); |
| 1524 | +/* Close child relations, but keep locks */ |
| 1525 | +if (childOID!=parentOID) |
| 1526 | +heap_close(newrelation,NoLock); |
1578 | 1527 | }
|
1579 |
| - |
1580 |
| -/* Close child relations, but keep locks */ |
1581 |
| -if (childOID!=parentOID) |
1582 |
| -heap_close(newrelation,NoLock); |
1583 | 1528 | }
|
1584 | 1529 |
|
1585 | 1530 | heap_close(oldrelation,NoLock);
|
@@ -1620,6 +1565,169 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
|
1620 | 1565 | root->append_rel_list=list_concat(root->append_rel_list,appinfos);
|
1621 | 1566 | }
|
1622 | 1567 |
|
| 1568 | +staticvoid |
| 1569 | +expand_partitioned_rtentry(PlannerInfo*root,RangeTblEntry*parentrte, |
| 1570 | +IndexparentRTindex,Relationparentrel, |
| 1571 | +PlanRowMark*parentrc,PartitionDescpartdesc, |
| 1572 | +LOCKMODElockmode, |
| 1573 | +bool*has_child,List**appinfos, |
| 1574 | +List**partitioned_child_rels) |
| 1575 | +{ |
| 1576 | +inti; |
| 1577 | + |
| 1578 | +check_stack_depth(); |
| 1579 | + |
| 1580 | +for (i=0;i<partdesc->nparts;i++) |
| 1581 | +{ |
| 1582 | +OidchildOID=partdesc->oids[i]; |
| 1583 | +Relationchildrel; |
| 1584 | + |
| 1585 | +/* Open rel; we already have required locks */ |
| 1586 | +childrel=heap_open(childOID,NoLock); |
| 1587 | + |
| 1588 | +/* As in expand_inherited_rtentry, skip non-local temp tables */ |
| 1589 | +if (RELATION_IS_OTHER_TEMP(childrel)) |
| 1590 | +{ |
| 1591 | +heap_close(childrel,lockmode); |
| 1592 | +continue; |
| 1593 | +} |
| 1594 | + |
| 1595 | +expand_single_inheritance_child(root,parentrte,parentRTindex, |
| 1596 | +parentrel,parentrc,childrel, |
| 1597 | +has_child,appinfos, |
| 1598 | +partitioned_child_rels); |
| 1599 | + |
| 1600 | +/* If this child is itself partitioned, recurse */ |
| 1601 | +if (childrel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE) |
| 1602 | +expand_partitioned_rtentry(root,parentrte,parentRTindex, |
| 1603 | +parentrel,parentrc, |
| 1604 | +RelationGetPartitionDesc(childrel), |
| 1605 | +lockmode, |
| 1606 | +has_child,appinfos, |
| 1607 | +partitioned_child_rels); |
| 1608 | + |
| 1609 | +/* Close child relation, but keep locks */ |
| 1610 | +heap_close(childrel,NoLock); |
| 1611 | +} |
| 1612 | +} |
| 1613 | + |
| 1614 | +/* |
| 1615 | + * expand_single_inheritance_child |
| 1616 | + *Expand a single inheritance child, if needed. |
| 1617 | + * |
| 1618 | + * If this is a temp table of another backend, we'll return without doing |
| 1619 | + * anything at all. Otherwise, we'll set "has_child" to true, build a |
| 1620 | + * RangeTblEntry and either a PartitionedChildRelInfo or AppendRelInfo as |
| 1621 | + * appropriate, plus maybe a PlanRowMark. |
| 1622 | + */ |
| 1623 | +staticvoid |
| 1624 | +expand_single_inheritance_child(PlannerInfo*root,RangeTblEntry*parentrte, |
| 1625 | +IndexparentRTindex,Relationparentrel, |
| 1626 | +PlanRowMark*parentrc,Relationchildrel, |
| 1627 | +bool*has_child,List**appinfos, |
| 1628 | +List**partitioned_child_rels) |
| 1629 | +{ |
| 1630 | +Query*parse=root->parse; |
| 1631 | +OidparentOID=RelationGetRelid(parentrel); |
| 1632 | +OidchildOID=RelationGetRelid(childrel); |
| 1633 | +RangeTblEntry*childrte; |
| 1634 | +IndexchildRTindex; |
| 1635 | +AppendRelInfo*appinfo; |
| 1636 | + |
| 1637 | +/* |
| 1638 | + * Build an RTE for the child, and attach to query's rangetable list. We |
| 1639 | + * copy most fields of the parent's RTE, but replace relation OID and |
| 1640 | + * relkind, and set inh = false. Also, set requiredPerms to zero since |
| 1641 | + * all required permissions checks are done on the original RTE. Likewise, |
| 1642 | + * set the child's securityQuals to empty, because we only want to apply |
| 1643 | + * the parent's RLS conditions regardless of what RLS properties |
| 1644 | + * individual children may have. (This is an intentional choice to make |
| 1645 | + * inherited RLS work like regular permissions checks.) The parent |
| 1646 | + * securityQuals will be propagated to children along with other base |
| 1647 | + * restriction clauses, so we don't need to do it here. |
| 1648 | + */ |
| 1649 | +childrte=copyObject(parentrte); |
| 1650 | +childrte->relid=childOID; |
| 1651 | +childrte->relkind=childrel->rd_rel->relkind; |
| 1652 | +childrte->inh= false; |
| 1653 | +childrte->requiredPerms=0; |
| 1654 | +childrte->securityQuals=NIL; |
| 1655 | +parse->rtable=lappend(parse->rtable,childrte); |
| 1656 | +childRTindex=list_length(parse->rtable); |
| 1657 | + |
| 1658 | +/* |
| 1659 | + * Build an AppendRelInfo for this parent and child, unless the child is a |
| 1660 | + * partitioned table. |
| 1661 | + */ |
| 1662 | +if (childrte->relkind!=RELKIND_PARTITIONED_TABLE) |
| 1663 | +{ |
| 1664 | +/* Remember if we saw a real child. */ |
| 1665 | +if (childOID!=parentOID) |
| 1666 | +*has_child= true; |
| 1667 | + |
| 1668 | +appinfo=makeNode(AppendRelInfo); |
| 1669 | +appinfo->parent_relid=parentRTindex; |
| 1670 | +appinfo->child_relid=childRTindex; |
| 1671 | +appinfo->parent_reltype=parentrel->rd_rel->reltype; |
| 1672 | +appinfo->child_reltype=childrel->rd_rel->reltype; |
| 1673 | +make_inh_translation_list(parentrel,childrel,childRTindex, |
| 1674 | +&appinfo->translated_vars); |
| 1675 | +appinfo->parent_reloid=parentOID; |
| 1676 | +*appinfos=lappend(*appinfos,appinfo); |
| 1677 | + |
| 1678 | +/* |
| 1679 | + * Translate the column permissions bitmaps to the child's attnums (we |
| 1680 | + * have to build the translated_vars list before we can do this). But |
| 1681 | + * if this is the parent table, leave copyObject's result alone. |
| 1682 | + * |
| 1683 | + * Note: we need to do this even though the executor won't run any |
| 1684 | + * permissions checks on the child RTE. The insertedCols/updatedCols |
| 1685 | + * bitmaps may be examined for trigger-firing purposes. |
| 1686 | + */ |
| 1687 | +if (childOID!=parentOID) |
| 1688 | +{ |
| 1689 | +childrte->selectedCols=translate_col_privs(parentrte->selectedCols, |
| 1690 | +appinfo->translated_vars); |
| 1691 | +childrte->insertedCols=translate_col_privs(parentrte->insertedCols, |
| 1692 | +appinfo->translated_vars); |
| 1693 | +childrte->updatedCols=translate_col_privs(parentrte->updatedCols, |
| 1694 | +appinfo->translated_vars); |
| 1695 | +} |
| 1696 | +} |
| 1697 | +else |
| 1698 | +*partitioned_child_rels=lappend_int(*partitioned_child_rels, |
| 1699 | +childRTindex); |
| 1700 | + |
| 1701 | +/* |
| 1702 | + * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE. |
| 1703 | + */ |
| 1704 | +if (parentrc) |
| 1705 | +{ |
| 1706 | +PlanRowMark*childrc=makeNode(PlanRowMark); |
| 1707 | + |
| 1708 | +childrc->rti=childRTindex; |
| 1709 | +childrc->prti=parentRTindex; |
| 1710 | +childrc->rowmarkId=parentrc->rowmarkId; |
| 1711 | +/* Reselect rowmark type, because relkind might not match parent */ |
| 1712 | +childrc->markType=select_rowmark_type(childrte,parentrc->strength); |
| 1713 | +childrc->allMarkTypes= (1 <<childrc->markType); |
| 1714 | +childrc->strength=parentrc->strength; |
| 1715 | +childrc->waitPolicy=parentrc->waitPolicy; |
| 1716 | + |
| 1717 | +/* |
| 1718 | + * We mark RowMarks for partitioned child tables as parent RowMarks so |
| 1719 | + * that the executor ignores them (except their existence means that |
| 1720 | + * the child tables be locked using appropriate mode). |
| 1721 | + */ |
| 1722 | +childrc->isParent= (childrte->relkind==RELKIND_PARTITIONED_TABLE); |
| 1723 | + |
| 1724 | +/* Include child's rowmark type in parent's allMarkTypes */ |
| 1725 | +parentrc->allMarkTypes |=childrc->allMarkTypes; |
| 1726 | + |
| 1727 | +root->rowMarks=lappend(root->rowMarks,childrc); |
| 1728 | +} |
| 1729 | +} |
| 1730 | + |
1623 | 1731 | /*
|
1624 | 1732 | * make_inh_translation_list
|
1625 | 1733 | * Build the list of translations from parent Vars to child Vars for
|
|