|
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 |
|