| Line | Hits | Source | Commit |
|---|---|---|---|
| 1615 | 118 | pg_get_propgraphdef(PG_FUNCTION_ARGS) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1616 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1617 | 118 | Oid pgrelid = PG_GETARG_OID(0); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1618 | 118 | StringInfoData buf; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1619 | 118 | HeapTuple classtup; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1620 | 118 | Form_pg_class classform; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1621 | 118 | char *name; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1622 | 118 | char *nsp; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1623 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1624 | 118 | initStringInfo(&buf); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1625 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1626 | 118 | classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(pgrelid)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1627 | 118 | if (!HeapTupleIsValid(classtup)) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1628 | 0 | PG_RETURN_NULL(); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1629 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1630 | 118 | classform = (Form_pg_class) GETSTRUCT(classtup); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1631 | 118 | name = NameStr(classform->relname); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1632 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1633 | 118 | if (classform->relkind != RELKIND_PROPGRAPH) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1634 | 3 | ereport(ERROR, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1635 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1636 | - | errmsg("\"%s\" is not a property graph", name))); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1637 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1638 | 115 | nsp = get_namespace_name(classform->relnamespace); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1639 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1640 | 115 | appendStringInfo(&buf, "CREATE PROPERTY GRAPH %s", | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1641 | - | quote_qualified_identifier(nsp, name)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1642 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1643 | 115 | ReleaseSysCache(classtup); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1644 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1645 | 115 | make_propgraphdef_elements(&buf, pgrelid, PGEKIND_VERTEX); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1646 | 115 | make_propgraphdef_elements(&buf, pgrelid, PGEKIND_EDGE); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1647 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1648 | 115 | PG_RETURN_TEXT_P(string_to_text(buf.data)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1649 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1657 | 230 | make_propgraphdef_elements(StringInfo buf, Oid pgrelid, char pgekind) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1658 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1659 | 230 | Relation pgerel; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1660 | 230 | ScanKeyData scankey[1]; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1661 | 230 | SysScanDesc scan; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1662 | 230 | bool first; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1663 | 230 | HeapTuple tup; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1664 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1665 | 230 | pgerel = table_open(PropgraphElementRelationId, AccessShareLock); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1666 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1667 | 230 | ScanKeyInit(&scankey[0], | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1668 | - | Anum_pg_propgraph_element_pgepgid, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1669 | - | BTEqualStrategyNumber, F_OIDEQ, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1670 | - | ObjectIdGetDatum(pgrelid)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1671 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1672 | 230 | scan = systable_beginscan(pgerel, PropgraphElementAliasIndexId, true, NULL, 1, scankey); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1673 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1674 | 230 | first = true; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1675 | 940 | while ((tup = systable_getnext(scan))) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1676 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1677 | 710 | Form_pg_propgraph_element pgeform = (Form_pg_propgraph_element) GETSTRUCT(tup); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1678 | 710 | char *relname; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1679 | 710 | Datum datum; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1680 | 710 | bool isnull; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1681 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1682 | 710 | if (pgeform->pgekind != pgekind) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1683 | 355 | continue; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1684 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1685 | 355 | if (first) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1686 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1687 | 152 | appendStringInfo(buf, "\n %s TABLES (\n", pgekind == PGEKIND_VERTEX ? "VERTEX" : "EDGE"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1688 | 152 | first = false; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1689 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1690 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1691 | 203 | appendStringInfo(buf, ",\n"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1692 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1693 | 355 | relname = get_rel_name(pgeform->pgerelid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1694 | 355 | if (relname && strcmp(relname, NameStr(pgeform->pgealias)) == 0) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1695 | 355 | appendStringInfo(buf, " %s", | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1696 | - | generate_relation_name(pgeform->pgerelid, NIL)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1697 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1698 | 0 | appendStringInfo(buf, " %s AS %s", | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1699 | - | generate_relation_name(pgeform->pgerelid, NIL), | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1700 | 0 | NameStr(pgeform->pgealias)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1701 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1702 | 355 | datum = heap_getattr(tup, Anum_pg_propgraph_element_pgekey, RelationGetDescr(pgerel), &isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1703 | 355 | if (!isnull) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1704 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1705 | 355 | appendStringInfoString(buf, " KEY ("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1706 | 355 | decompile_column_index_array(datum, pgeform->pgerelid, false, buf); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1707 | 355 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1708 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1709 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1710 | 0 | elog(ERROR, "null pgekey for element %u", pgeform->oid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1711 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1712 | 355 | if (pgekind == PGEKIND_EDGE) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1713 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1714 | 156 | Datum srckey; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1715 | 156 | Datum srcref; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1716 | 156 | Datum destkey; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1717 | 156 | Datum destref; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1718 | 156 | HeapTuple tup2; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1719 | 156 | Form_pg_propgraph_element pgeform2; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1720 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1721 | 156 | datum = heap_getattr(tup, Anum_pg_propgraph_element_pgesrckey, RelationGetDescr(pgerel), &isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1722 | 156 | srckey = isnull ? 0 : datum; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1723 | 156 | datum = heap_getattr(tup, Anum_pg_propgraph_element_pgesrcref, RelationGetDescr(pgerel), &isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1724 | 156 | srcref = isnull ? 0 : datum; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1725 | 156 | datum = heap_getattr(tup, Anum_pg_propgraph_element_pgedestkey, RelationGetDescr(pgerel), &isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1726 | 156 | destkey = isnull ? 0 : datum; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1727 | 156 | datum = heap_getattr(tup, Anum_pg_propgraph_element_pgedestref, RelationGetDescr(pgerel), &isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1728 | 156 | destref = isnull ? 0 : datum; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1729 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1730 | 156 | appendStringInfoString(buf, " SOURCE"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1731 | 156 | tup2 = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(pgeform->pgesrcvertexid)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1732 | 156 | if (!tup2) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1733 | 0 | elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgesrcvertexid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1734 | 156 | pgeform2 = (Form_pg_propgraph_element) GETSTRUCT(tup2); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1735 | 156 | if (srckey) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1736 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1737 | 156 | appendStringInfoString(buf, " KEY ("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1738 | 156 | decompile_column_index_array(srckey, pgeform->pgerelid, false, buf); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1739 | 156 | appendStringInfo(buf, ") REFERENCES %s (", NameStr(pgeform2->pgealias)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1740 | 156 | decompile_column_index_array(srcref, pgeform2->pgerelid, false, buf); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1741 | 156 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1742 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1743 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1744 | 0 | appendStringInfo(buf, " %s ", NameStr(pgeform2->pgealias)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1745 | 156 | ReleaseSysCache(tup2); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1746 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1747 | 156 | appendStringInfoString(buf, " DESTINATION"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1748 | 156 | tup2 = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(pgeform->pgedestvertexid)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1749 | 156 | if (!tup2) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1750 | 0 | elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgedestvertexid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1751 | 156 | pgeform2 = (Form_pg_propgraph_element) GETSTRUCT(tup2); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1752 | 156 | if (destkey) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1753 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1754 | 156 | appendStringInfoString(buf, " KEY ("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1755 | 156 | decompile_column_index_array(destkey, pgeform->pgerelid, false, buf); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1756 | 156 | appendStringInfo(buf, ") REFERENCES %s (", NameStr(pgeform2->pgealias)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1757 | 156 | decompile_column_index_array(destref, pgeform2->pgerelid, false, buf); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1758 | 156 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1759 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1760 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1761 | 0 | appendStringInfo(buf, " %s", NameStr(pgeform2->pgealias)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1762 | 156 | ReleaseSysCache(tup2); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1763 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1764 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1765 | 355 | make_propgraphdef_labels(buf, pgeform->oid, NameStr(pgeform->pgealias), pgeform->pgerelid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1766 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1767 | 230 | if (!first) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1768 | 152 | appendStringInfo(buf, "\n )"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1769 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1770 | 230 | systable_endscan(scan); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1771 | 230 | table_close(pgerel, AccessShareLock); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1772 | 230 | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1779 | 355 | make_propgraphdef_labels(StringInfo buf, Oid elid, const char *elalias, Oid elrelid) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1780 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1781 | 355 | Relation pglrel; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1782 | 355 | ScanKeyData scankey[1]; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1783 | 355 | SysScanDesc scan; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1784 | 355 | int count; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1785 | 355 | HeapTuple tup; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1786 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1787 | 355 | pglrel = table_open(PropgraphElementLabelRelationId, AccessShareLock); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1788 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1789 | 355 | ScanKeyInit(&scankey[0], | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1790 | - | Anum_pg_propgraph_element_label_pgelelid, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1791 | - | BTEqualStrategyNumber, F_OIDEQ, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1792 | - | ObjectIdGetDatum(elid)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1793 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1794 | 355 | count = 0; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1795 | 355 | scan = systable_beginscan(pglrel, PropgraphElementLabelElementLabelIndexId, true, NULL, 1, scankey); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1796 | 812 | while ((tup = systable_getnext(scan))) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1797 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1798 | 457 | count++; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1799 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1800 | 355 | systable_endscan(scan); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1801 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1802 | 355 | scan = systable_beginscan(pglrel, PropgraphElementLabelElementLabelIndexId, true, NULL, 1, scankey); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1803 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1804 | 812 | while ((tup = systable_getnext(scan))) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1805 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1806 | 457 | Form_pg_propgraph_element_label pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1807 | 457 | const char *labelname; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1808 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1809 | 457 | labelname = get_propgraph_label_name(pgelform->pgellabelid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1810 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1811 | 457 | if (strcmp(labelname, elalias) == 0) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1812 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1813 | - | /* If the default label is the only label, don't print anything. */ | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1814 | 243 | if (count != 1) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1815 | 30 | appendStringInfo(buf, " DEFAULT LABEL"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1816 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1817 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1818 | 214 | appendStringInfo(buf, " LABEL %s", quote_identifier(labelname)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1819 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1820 | 457 | make_propgraphdef_properties(buf, pgelform->oid, elrelid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1821 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1822 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1823 | 355 | systable_endscan(scan); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1824 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1825 | 355 | table_close(pglrel, AccessShareLock); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1826 | 355 | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1833 | 709 | propdata_by_name_cmp(const ListCell *a, const ListCell *b) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1834 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1835 | 709 | List *la = lfirst_node(List, a); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1836 | 709 | List *lb = lfirst_node(List, b); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1837 | 709 | char *pna = strVal(linitial(la)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1838 | 709 | char *pnb = strVal(linitial(lb)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1839 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1840 | 709 | return strcmp(pna, pnb); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1841 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1849 | 457 | make_propgraphdef_properties(StringInfo buf, Oid ellabelid, Oid elrelid) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1850 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1851 | 457 | Relation plprel; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1852 | 457 | ScanKeyData scankey[1]; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1853 | 457 | SysScanDesc scan; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1854 | 457 | HeapTuple tup; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1855 | 457 | List *outlist = NIL; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1856 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1857 | 457 | plprel = table_open(PropgraphLabelPropertyRelationId, AccessShareLock); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1858 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1859 | 457 | ScanKeyInit(&scankey[0], | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1860 | - | Anum_pg_propgraph_label_property_plpellabelid, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1861 | - | BTEqualStrategyNumber, F_OIDEQ, | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1862 | - | ObjectIdGetDatum(ellabelid)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1863 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1864 | - | /* | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1865 | - | * We want to output the properties in a deterministic order. So we first | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1866 | - | * read all the data, then sort, then print it. | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1867 | - | */ | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1868 | 457 | scan = systable_beginscan(plprel, PropgraphLabelPropertyLabelPropIndexId, true, NULL, 1, scankey); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1869 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1870 | 1484 | while ((tup = systable_getnext(scan))) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1871 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1872 | 1027 | Form_pg_propgraph_label_property plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1873 | 1027 | Datum exprDatum; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1874 | 1027 | bool isnull; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1875 | 1027 | char *tmp; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1876 | 1027 | Node *expr; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1877 | 1027 | char *propname; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1878 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1879 | 1027 | exprDatum = heap_getattr(tup, Anum_pg_propgraph_label_property_plpexpr, RelationGetDescr(plprel), &isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1880 | 1027 | Assert(!isnull); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1881 | 1027 | tmp = TextDatumGetCString(exprDatum); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1882 | 1027 | expr = stringToNode(tmp); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1883 | 1027 | pfree(tmp); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1884 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1885 | 1027 | propname = get_propgraph_property_name(plpform->plppropid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1886 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1887 | 1027 | outlist = lappend(outlist, list_make2(makeString(propname), expr)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1888 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1889 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1890 | 457 | systable_endscan(scan); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1891 | 457 | table_close(plprel, AccessShareLock); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1892 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1893 | 457 | list_sort(outlist, propdata_by_name_cmp); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1894 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1895 | 457 | if (outlist) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1896 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1897 | 449 | List *context; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1898 | 449 | ListCell *lc; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1899 | 449 | bool first = true; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1900 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1901 | 449 | context = deparse_context_for(get_relation_name(elrelid), elrelid); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1902 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1903 | 449 | appendStringInfo(buf, " PROPERTIES ("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1904 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1905 | 1476 | foreach(lc, outlist) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1906 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1907 | 1027 | List *data = lfirst_node(List, lc); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1908 | 1027 | char *propname = strVal(linitial(data)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1909 | 1027 | Node *expr = lsecond(data); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1910 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1911 | 1027 | if (first) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1912 | - | first = false; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1913 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1914 | 578 | appendStringInfo(buf, ", "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1915 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1916 | 1027 | if (IsA(expr, Var) && strcmp(propname, get_attname(elrelid, castNode(Var, expr)->varattno, false)) == 0) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1917 | 830 | appendStringInfo(buf, "%s", propname); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1918 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1919 | 197 | appendStringInfo(buf, "%s AS %s", | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1920 | - | deparse_expression_pretty(expr, context, false, false, 0, 0), | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1921 | - | propname); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1922 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1923 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 1924 | 449 | appendStringInfo(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1925 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1926 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1927 | 8 | appendStringInfo(buf, " NO PROPERTIES"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1928 | 457 | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 7923 | 39 | get_graph_label_expr(Node *label_expr, deparse_context *context) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7924 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7925 | 39 | StringInfo buf = context->buf; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7926 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7927 | 39 | check_stack_depth(); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7928 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7929 | 39 | switch (nodeTag(label_expr)) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7930 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7931 | 39 | case T_GraphLabelRef: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7932 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7933 | 39 | GraphLabelRef *lref = (GraphLabelRef *) label_expr; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7934 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7935 | 39 | appendStringInfoString(buf, quote_identifier(get_propgraph_label_name(lref->labelid))); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7936 | 39 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7937 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7938 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7939 | 0 | case T_BoolExpr: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7940 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7941 | 0 | BoolExpr *be = (BoolExpr *) label_expr; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7942 | 0 | ListCell *lc; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7943 | 0 | bool first = true; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7944 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7945 | 0 | Assert(be->boolop == OR_EXPR); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7946 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7947 | 0 | foreach(lc, be->args) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7948 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7949 | 0 | if (!first) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7950 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7951 | 0 | if (be->boolop == OR_EXPR) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7952 | 0 | appendStringInfoString(buf, "|"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7953 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7954 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7955 | - | first = false; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7956 | 0 | get_graph_label_expr(lfirst(lc), context); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7957 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7958 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7959 | 0 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7960 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7961 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7962 | 0 | default: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7963 | 0 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(label_expr)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7964 | - | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7965 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7966 | 39 | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 7972 | 13 | get_path_pattern_expr_def(List *path_pattern_expr, deparse_context *context) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7973 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7974 | 13 | StringInfo buf = context->buf; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7975 | 13 | ListCell *lc; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7976 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7977 | 52 | foreach(lc, path_pattern_expr) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7978 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7979 | 39 | GraphElementPattern *gep = lfirst_node(GraphElementPattern, lc); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7980 | 39 | const char *sep = ""; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7981 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7982 | 39 | switch (gep->kind) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7983 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7984 | 26 | case VERTEX_PATTERN: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7985 | 26 | appendStringInfoString(buf, "("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7986 | 26 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7987 | 0 | case EDGE_PATTERN_LEFT: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7988 | 0 | appendStringInfoString(buf, "<-["); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7989 | 0 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7990 | 13 | case EDGE_PATTERN_RIGHT: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7991 | - | case EDGE_PATTERN_ANY: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7992 | 13 | appendStringInfoString(buf, "-["); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7993 | 13 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7994 | 0 | case PAREN_EXPR: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7995 | 0 | appendStringInfoString(buf, "("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7996 | 0 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7997 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 7998 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 7999 | 39 | if (gep->variable) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8000 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8001 | 26 | appendStringInfoString(buf, gep->variable); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8002 | 26 | sep = " "; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8003 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8004 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8005 | 39 | if (gep->labelexpr) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8006 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8007 | 39 | appendStringInfoString(buf, sep); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8008 | 39 | appendStringInfoString(buf, "IS "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8009 | 39 | get_graph_label_expr(gep->labelexpr, context); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8010 | 39 | sep = " "; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8011 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8012 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8013 | 39 | if (gep->subexpr) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8014 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8015 | 0 | appendStringInfoString(buf, sep); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8016 | 0 | get_path_pattern_expr_def(gep->subexpr, context); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8017 | 0 | sep = " "; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8018 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8019 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8020 | 39 | if (gep->whereClause) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8021 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8022 | 13 | appendStringInfoString(buf, sep); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8023 | 13 | appendStringInfoString(buf, "WHERE "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8024 | 13 | get_rule_expr(gep->whereClause, context, false); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8025 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8026 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8027 | 39 | switch (gep->kind) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8028 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8029 | 26 | case VERTEX_PATTERN: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8030 | 26 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8031 | 26 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8032 | 0 | case EDGE_PATTERN_LEFT: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8033 | - | case EDGE_PATTERN_ANY: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8034 | 0 | appendStringInfoString(buf, "]-"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8035 | 0 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8036 | 13 | case EDGE_PATTERN_RIGHT: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8037 | 13 | appendStringInfoString(buf, "]->"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8038 | 13 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8039 | 0 | case PAREN_EXPR: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8040 | 0 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8041 | 0 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8042 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8043 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8044 | 39 | if (gep->quantifier) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8045 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8046 | 0 | int lower = linitial_int(gep->quantifier); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8047 | 0 | int upper = lsecond_int(gep->quantifier); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8048 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8049 | 0 | appendStringInfo(buf, "{%d,%d}", lower, upper); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8050 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8051 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8052 | 13 | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 8058 | 13 | get_graph_pattern_def(GraphPattern *graph_pattern, deparse_context *context) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8059 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8060 | 13 | StringInfo buf = context->buf; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8061 | 13 | ListCell *lc; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8062 | 13 | bool first = true; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8063 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8064 | 26 | foreach(lc, graph_pattern->path_pattern_list) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8065 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8066 | 13 | List *path_pattern_expr = lfirst_node(List, lc); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8067 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8068 | 13 | if (!first) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8069 | 0 | appendStringInfoString(buf, ", "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8070 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8071 | - | first = false; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8072 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8073 | 13 | get_path_pattern_expr_def(path_pattern_expr, context); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8074 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8075 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 8076 | 13 | if (graph_pattern->whereClause) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8077 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8078 | 0 | appendStringInfoString(buf, "WHERE "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8079 | 0 | get_rule_expr(graph_pattern->whereClause, context, false); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8080 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8081 | 13 | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 8514 | - | get_name_for_var_field(Var *var, int fieldno, | - |
| 8515 | - | int levelsup, deparse_context *context) | - |
| 8516 | - | { | - |
| 8517 | - | RangeTblEntry *rte; | - |
| 8518 | - | AttrNumber attnum; | - |
| 8519 | - | int netlevelsup; | - |
| 8520 | - | deparse_namespace *dpns; | - |
| 8521 | - | int varno; | - |
| 8522 | - | AttrNumber varattno; | - |
| 8523 | - | TupleDesc tupleDesc; | - |
| 8524 | - | Node *expr; | - |
| 8525 | - | - | |
| 8526 | - | /* | - |
| 8527 | - | * If it's a RowExpr that was expanded from a whole-row Var, use the | - |
| 8528 | - | * column names attached to it. (We could let get_expr_result_tupdesc() | - |
| 8529 | - | * handle this, but it's much cheaper to just pull out the name we need.) | - |
| 8530 | - | */ | - |
| 8531 | - | if (IsA(var, RowExpr)) | - |
| 8532 | - | { | - |
| 8533 | - | RowExpr *r = (RowExpr *) var; | - |
| 8534 | - | - | |
| 8535 | - | if (fieldno > 0 && fieldno <= list_length(r->colnames)) | - |
| 8536 | - | return strVal(list_nth(r->colnames, fieldno - 1)); | - |
| 8537 | - | } | - |
| 8538 | - | - | |
| 8539 | - | /* | - |
| 8540 | - | * If it's a Param of type RECORD, try to find what the Param refers to. | - |
| 8541 | - | */ | - |
| 8542 | - | if (IsA(var, Param)) | - |
| 8543 | - | { | - |
| 8544 | - | Param *param = (Param *) var; | - |
| 8545 | - | ListCell *ancestor_cell; | - |
| 8546 | - | - | |
| 8547 | - | expr = find_param_referent(param, context, &dpns, &ancestor_cell); | - |
| 8548 | - | if (expr) | - |
| 8549 | - | { | - |
| 8550 | - | /* Found a match, so recurse to decipher the field name */ | - |
| 8551 | - | deparse_namespace save_dpns; | - |
| 8552 | - | const char *result; | - |
| 8553 | - | - | |
| 8554 | - | push_ancestor_plan(dpns, ancestor_cell, &save_dpns); | - |
| 8555 | - | result = get_name_for_var_field((Var *) expr, fieldno, | - |
| 8556 | - | 0, context); | - |
| 8557 | - | pop_ancestor_plan(dpns, &save_dpns); | - |
| 8558 | - | return result; | - |
| 8559 | - | } | - |
| 8560 | - | } | - |
| 8561 | - | - | |
| 8562 | - | /* | - |
| 8563 | - | * If it's a Var of type RECORD, we have to find what the Var refers to; | - |
| 8564 | - | * if not, we can use get_expr_result_tupdesc(). | - |
| 8565 | - | */ | - |
| 8566 | - | if (!IsA(var, Var) || | - |
| 8567 | - | var->vartype != RECORDOID) | - |
| 8568 | - | { | - |
| 8569 | - | tupleDesc = get_expr_result_tupdesc((Node *) var, false); | - |
| 8570 | - | /* Got the tupdesc, so we can extract the field name */ | - |
| 8571 | - | Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); | - |
| 8572 | - | return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname); | - |
| 8573 | - | } | - |
| 8574 | - | - | |
| 8575 | - | /* Find appropriate nesting depth */ | - |
| 8576 | - | netlevelsup = var->varlevelsup + levelsup; | - |
| 8577 | - | if (netlevelsup >= list_length(context->namespaces)) | - |
| 8578 | - | elog(ERROR, "bogus varlevelsup: %d offset %d", | - |
| 8579 | - | var->varlevelsup, levelsup); | - |
| 8580 | - | dpns = (deparse_namespace *) list_nth(context->namespaces, | - |
| 8581 | - | netlevelsup); | - |
| 8582 | - | - | |
| 8583 | - | /* | - |
| 8584 | - | * If we have a syntactic referent for the Var, and we're working from a | - |
| 8585 | - | * parse tree, prefer to use the syntactic referent. Otherwise, fall back | - |
| 8586 | - | * on the semantic referent. (See comments in get_variable().) | - |
| 8587 | - | */ | - |
| 8588 | - | if (var->varnosyn > 0 && dpns->plan == NULL) | - |
| 8589 | - | { | - |
| 8590 | - | varno = var->varnosyn; | - |
| 8591 | - | varattno = var->varattnosyn; | - |
| 8592 | - | } | - |
| 8593 | - | else | - |
| 8594 | - | { | - |
| 8595 | - | varno = var->varno; | - |
| 8596 | - | varattno = var->varattno; | - |
| 8597 | - | } | - |
| 8598 | - | - | |
| 8599 | - | /* | - |
| 8600 | - | * Try to find the relevant RTE in this rtable. In a plan tree, it's | - |
| 8601 | - | * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig | - |
| 8602 | - | * down into the subplans, or INDEX_VAR, which is resolved similarly. | - |
| 8603 | - | * | - |
| 8604 | - | * Note: unlike get_variable and resolve_special_varno, we need not worry | - |
| 8605 | - | * about inheritance mapping: a child Var should have the same datatype as | - |
| 8606 | - | * its parent, and here we're really only interested in the Var's type. | - |
| 8607 | - | */ | - |
| 8608 | - | if (varno >= 1 && varno <= list_length(dpns->rtable)) | - |
| 8609 | - | { | - |
| 8610 | - | rte = rt_fetch(varno, dpns->rtable); | - |
| 8611 | - | attnum = varattno; | - |
| 8612 | - | } | - |
| 8613 | - | else if (varno == OUTER_VAR && dpns->outer_tlist) | - |
| 8614 | - | { | - |
| 8615 | - | TargetEntry *tle; | - |
| 8616 | - | deparse_namespace save_dpns; | - |
| 8617 | - | const char *result; | - |
| 8618 | - | - | |
| 8619 | - | tle = get_tle_by_resno(dpns->outer_tlist, varattno); | - |
| 8620 | - | if (!tle) | - |
| 8621 | - | elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno); | - |
| 8622 | - | - | |
| 8623 | - | Assert(netlevelsup == 0); | - |
| 8624 | - | push_child_plan(dpns, dpns->outer_plan, &save_dpns); | - |
| 8625 | - | - | |
| 8626 | - | result = get_name_for_var_field((Var *) tle->expr, fieldno, | - |
| 8627 | - | levelsup, context); | - |
| 8628 | - | - | |
| 8629 | - | pop_child_plan(dpns, &save_dpns); | - |
| 8630 | - | return result; | - |
| 8631 | - | } | - |
| 8632 | - | else if (varno == INNER_VAR && dpns->inner_tlist) | - |
| 8633 | - | { | - |
| 8634 | - | TargetEntry *tle; | - |
| 8635 | - | deparse_namespace save_dpns; | - |
| 8636 | - | const char *result; | - |
| 8637 | - | - | |
| 8638 | - | tle = get_tle_by_resno(dpns->inner_tlist, varattno); | - |
| 8639 | - | if (!tle) | - |
| 8640 | - | elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno); | - |
| 8641 | - | - | |
| 8642 | - | Assert(netlevelsup == 0); | - |
| 8643 | - | push_child_plan(dpns, dpns->inner_plan, &save_dpns); | - |
| 8644 | - | - | |
| 8645 | - | result = get_name_for_var_field((Var *) tle->expr, fieldno, | - |
| 8646 | - | levelsup, context); | - |
| 8647 | - | - | |
| 8648 | - | pop_child_plan(dpns, &save_dpns); | - |
| 8649 | - | return result; | - |
| 8650 | - | } | - |
| 8651 | - | else if (varno == INDEX_VAR && dpns->index_tlist) | - |
| 8652 | - | { | - |
| 8653 | - | TargetEntry *tle; | - |
| 8654 | - | const char *result; | - |
| 8655 | - | - | |
| 8656 | - | tle = get_tle_by_resno(dpns->index_tlist, varattno); | - |
| 8657 | - | if (!tle) | - |
| 8658 | - | elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno); | - |
| 8659 | - | - | |
| 8660 | - | Assert(netlevelsup == 0); | - |
| 8661 | - | - | |
| 8662 | - | result = get_name_for_var_field((Var *) tle->expr, fieldno, | - |
| 8663 | - | levelsup, context); | - |
| 8664 | - | - | |
| 8665 | - | return result; | - |
| 8666 | - | } | - |
| 8667 | - | else | - |
| 8668 | - | { | - |
| 8669 | - | elog(ERROR, "bogus varno: %d", varno); | - |
| 8670 | - | return NULL; /* keep compiler quiet */ | - |
| 8671 | - | } | - |
| 8672 | - | - | |
| 8673 | - | if (attnum == InvalidAttrNumber) | - |
| 8674 | - | { | - |
| 8675 | - | /* Var is whole-row reference to RTE, so select the right field */ | - |
| 8676 | - | return get_rte_attribute_name(rte, fieldno); | - |
| 8677 | - | } | - |
| 8678 | - | - | |
| 8679 | - | /* | - |
| 8680 | - | * This part has essentially the same logic as the parser's | - |
| 8681 | - | * expandRecordVariable() function, but we are dealing with a different | - |
| 8682 | - | * representation of the input context, and we only need one field name | - |
| 8683 | - | * not a TupleDesc. Also, we need special cases for finding subquery and | - |
| 8684 | - | * CTE subplans when deparsing Plan trees. | - |
| 8685 | - | */ | - |
| 8686 | - | expr = (Node *) var; /* default if we can't drill down */ | - |
| 8687 | - | - | |
| 8688 | - | switch (rte->rtekind) | - |
| 8689 | - | { | - |
| 8690 | - | case RTE_RELATION: | - |
| 8691 | - | case RTE_VALUES: | - |
| 8692 | - | case RTE_NAMEDTUPLESTORE: | - |
| 8693 | - | case RTE_GRAPH_TABLE: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 8694 | - | case RTE_RESULT: | - |
| 8695 | - | - | |
| 8696 | - | /* | - |
| 8697 | - | * This case should not occur: a column of a table, values list, | - |
| 8698 | - | * or ENR shouldn't have type RECORD. Fall through and fail (most | - |
| 8699 | - | * likely) at the bottom. | - |
| 8700 | - | */ | - |
| 8701 | - | break; | - |
| 8702 | - | case RTE_SUBQUERY: | - |
| 8703 | - | /* Subselect-in-FROM: examine sub-select's output expr */ | - |
| 8704 | - | { | - |
| 8705 | - | if (rte->subquery) | - |
| 8706 | - | { | - |
| 8707 | - | TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList, | - |
| 8708 | - | attnum); | - |
| 8709 | - | - | |
| 8710 | - | if (ste == NULL || ste->resjunk) | - |
| 8711 | - | elog(ERROR, "subquery %s does not have attribute %d", | - |
| 8712 | - | rte->eref->aliasname, attnum); | - |
| 8713 | - | expr = (Node *) ste->expr; | - |
| 8714 | - | if (IsA(expr, Var)) | - |
| 8715 | - | { | - |
| 8716 | - | /* | - |
| 8717 | - | * Recurse into the sub-select to see what its Var | - |
| 8718 | - | * refers to. We have to build an additional level of | - |
| 8719 | - | * namespace to keep in step with varlevelsup in the | - |
| 8720 | - | * subselect; furthermore, the subquery RTE might be | - |
| 8721 | - | * from an outer query level, in which case the | - |
| 8722 | - | * namespace for the subselect must have that outer | - |
| 8723 | - | * level as parent namespace. | - |
| 8724 | - | */ | - |
| 8725 | - | List *save_nslist = context->namespaces; | - |
| 8726 | - | List *parent_namespaces; | - |
| 8727 | - | deparse_namespace mydpns; | - |
| 8728 | - | const char *result; | - |
| 8729 | - | - | |
| 8730 | - | parent_namespaces = list_copy_tail(context->namespaces, | - |
| 8731 | - | netlevelsup); | - |
| 8732 | - | - | |
| 8733 | - | set_deparse_for_query(&mydpns, rte->subquery, | - |
| 8734 | - | parent_namespaces); | - |
| 8735 | - | - | |
| 8736 | - | context->namespaces = lcons(&mydpns, parent_namespaces); | - |
| 8737 | - | - | |
| 8738 | - | result = get_name_for_var_field((Var *) expr, fieldno, | - |
| 8739 | - | 0, context); | - |
| 8740 | - | - | |
| 8741 | - | context->namespaces = save_nslist; | - |
| 8742 | - | - | |
| 8743 | - | return result; | - |
| 8744 | - | } | - |
| 8745 | - | /* else fall through to inspect the expression */ | - |
| 8746 | - | } | - |
| 8747 | - | else | - |
| 8748 | - | { | - |
| 8749 | - | /* | - |
| 8750 | - | * We're deparsing a Plan tree so we don't have complete | - |
| 8751 | - | * RTE entries (in particular, rte->subquery is NULL). But | - |
| 8752 | - | * the only place we'd normally see a Var directly | - |
| 8753 | - | * referencing a SUBQUERY RTE is in a SubqueryScan plan | - |
| 8754 | - | * node, and we can look into the child plan's tlist | - |
| 8755 | - | * instead. An exception occurs if the subquery was | - |
| 8756 | - | * proven empty and optimized away: then we'd find such a | - |
| 8757 | - | * Var in a childless Result node, and there's nothing in | - |
| 8758 | - | * the plan tree that would let us figure out what it had | - |
| 8759 | - | * originally referenced. In that case, fall back on | - |
| 8760 | - | * printing "fN", analogously to the default column names | - |
| 8761 | - | * for RowExprs. | - |
| 8762 | - | */ | - |
| 8763 | - | TargetEntry *tle; | - |
| 8764 | - | deparse_namespace save_dpns; | - |
| 8765 | - | const char *result; | - |
| 8766 | - | - | |
| 8767 | - | if (!dpns->inner_plan) | - |
| 8768 | - | { | - |
| 8769 | - | char *dummy_name = palloc(32); | - |
| 8770 | - | - | |
| 8771 | - | Assert(dpns->plan && IsA(dpns->plan, Result)); | - |
| 8772 | - | snprintf(dummy_name, 32, "f%d", fieldno); | - |
| 8773 | - | return dummy_name; | - |
| 8774 | - | } | - |
| 8775 | - | Assert(dpns->plan && IsA(dpns->plan, SubqueryScan)); | - |
| 8776 | - | - | |
| 8777 | - | tle = get_tle_by_resno(dpns->inner_tlist, attnum); | - |
| 8778 | - | if (!tle) | - |
| 8779 | - | elog(ERROR, "bogus varattno for subquery var: %d", | - |
| 8780 | - | attnum); | - |
| 8781 | - | Assert(netlevelsup == 0); | - |
| 8782 | - | push_child_plan(dpns, dpns->inner_plan, &save_dpns); | - |
| 8783 | - | - | |
| 8784 | - | result = get_name_for_var_field((Var *) tle->expr, fieldno, | - |
| 8785 | - | levelsup, context); | - |
| 8786 | - | - | |
| 8787 | - | pop_child_plan(dpns, &save_dpns); | - |
| 8788 | - | return result; | - |
| 8789 | - | } | - |
| 8790 | - | } | - |
| 8791 | - | break; | - |
| 8792 | - | case RTE_JOIN: | - |
| 8793 | - | /* Join RTE --- recursively inspect the alias variable */ | - |
| 8794 | - | if (rte->joinaliasvars == NIL) | - |
| 8795 | - | elog(ERROR, "cannot decompile join alias var in plan tree"); | - |
| 8796 | - | Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars)); | - |
| 8797 | - | expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1); | - |
| 8798 | - | Assert(expr != NULL); | - |
| 8799 | - | /* we intentionally don't strip implicit coercions here */ | - |
| 8800 | - | if (IsA(expr, Var)) | - |
| 8801 | - | return get_name_for_var_field((Var *) expr, fieldno, | - |
| 8802 | - | var->varlevelsup + levelsup, | - |
| 8803 | - | context); | - |
| 8804 | - | /* else fall through to inspect the expression */ | - |
| 8805 | - | break; | - |
| 8806 | - | case RTE_FUNCTION: | - |
| 8807 | - | case RTE_TABLEFUNC: | - |
| 8808 | - | - | |
| 8809 | - | /* | - |
| 8810 | - | * We couldn't get here unless a function is declared with one of | - |
| 8811 | - | * its result columns as RECORD, which is not allowed. | - |
| 8812 | - | */ | - |
| 8813 | - | break; | - |
| 8814 | - | case RTE_CTE: | - |
| 8815 | - | /* CTE reference: examine subquery's output expr */ | - |
| 8816 | - | { | - |
| 8817 | - | CommonTableExpr *cte = NULL; | - |
| 8818 | - | Index ctelevelsup; | - |
| 8819 | - | ListCell *lc; | - |
| 8820 | - | - | |
| 8821 | - | /* | - |
| 8822 | - | * Try to find the referenced CTE using the namespace stack. | - |
| 8823 | - | */ | - |
| 8824 | - | ctelevelsup = rte->ctelevelsup + netlevelsup; | - |
| 8825 | - | if (ctelevelsup >= list_length(context->namespaces)) | - |
| 8826 | - | lc = NULL; | - |
| 8827 | - | else | - |
| 8828 | - | { | - |
| 8829 | - | deparse_namespace *ctedpns; | - |
| 8830 | - | - | |
| 8831 | - | ctedpns = (deparse_namespace *) | - |
| 8832 | - | list_nth(context->namespaces, ctelevelsup); | - |
| 8833 | - | foreach(lc, ctedpns->ctes) | - |
| 8834 | - | { | - |
| 8835 | - | cte = (CommonTableExpr *) lfirst(lc); | - |
| 8836 | - | if (strcmp(cte->ctename, rte->ctename) == 0) | - |
| 8837 | - | break; | - |
| 8838 | - | } | - |
| 8839 | - | } | - |
| 8840 | - | if (lc != NULL) | - |
| 8841 | - | { | - |
| 8842 | - | Query *ctequery = (Query *) cte->ctequery; | - |
| 8843 | - | TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte), | - |
| 8844 | - | attnum); | - |
| 8845 | - | - | |
| 8846 | - | if (ste == NULL || ste->resjunk) | - |
| 8847 | - | elog(ERROR, "CTE %s does not have attribute %d", | - |
| 8848 | - | rte->eref->aliasname, attnum); | - |
| 8849 | - | expr = (Node *) ste->expr; | - |
| 8850 | - | if (IsA(expr, Var)) | - |
| 8851 | - | { | - |
| 8852 | - | /* | - |
| 8853 | - | * Recurse into the CTE to see what its Var refers to. | - |
| 8854 | - | * We have to build an additional level of namespace | - |
| 8855 | - | * to keep in step with varlevelsup in the CTE; | - |
| 8856 | - | * furthermore it could be an outer CTE (compare | - |
| 8857 | - | * SUBQUERY case above). | - |
| 8858 | - | */ | - |
| 8859 | - | List *save_nslist = context->namespaces; | - |
| 8860 | - | List *parent_namespaces; | - |
| 8861 | - | deparse_namespace mydpns; | - |
| 8862 | - | const char *result; | - |
| 8863 | - | - | |
| 8864 | - | parent_namespaces = list_copy_tail(context->namespaces, | - |
| 8865 | - | ctelevelsup); | - |
| 8866 | - | - | |
| 8867 | - | set_deparse_for_query(&mydpns, ctequery, | - |
| 8868 | - | parent_namespaces); | - |
| 8869 | - | - | |
| 8870 | - | context->namespaces = lcons(&mydpns, parent_namespaces); | - |
| 8871 | - | - | |
| 8872 | - | result = get_name_for_var_field((Var *) expr, fieldno, | - |
| 8873 | - | 0, context); | - |
| 8874 | - | - | |
| 8875 | - | context->namespaces = save_nslist; | - |
| 8876 | - | - | |
| 8877 | - | return result; | - |
| 8878 | - | } | - |
| 8879 | - | /* else fall through to inspect the expression */ | - |
| 8880 | - | } | - |
| 8881 | - | else | - |
| 8882 | - | { | - |
| 8883 | - | /* | - |
| 8884 | - | * We're deparsing a Plan tree so we don't have a CTE | - |
| 8885 | - | * list. But the only places we'd normally see a Var | - |
| 8886 | - | * directly referencing a CTE RTE are in CteScan or | - |
| 8887 | - | * WorkTableScan plan nodes. For those cases, | - |
| 8888 | - | * set_deparse_plan arranged for dpns->inner_plan to be | - |
| 8889 | - | * the plan node that emits the CTE or RecursiveUnion | - |
| 8890 | - | * result, and we can look at its tlist instead. As | - |
| 8891 | - | * above, this can fail if the CTE has been proven empty, | - |
| 8892 | - | * in which case fall back to "fN". | - |
| 8893 | - | */ | - |
| 8894 | - | TargetEntry *tle; | - |
| 8895 | - | deparse_namespace save_dpns; | - |
| 8896 | - | const char *result; | - |
| 8897 | - | - | |
| 8898 | - | if (!dpns->inner_plan) | - |
| 8899 | - | { | - |
| 8900 | - | char *dummy_name = palloc(32); | - |
| 8901 | - | - | |
| 8902 | - | Assert(dpns->plan && IsA(dpns->plan, Result)); | - |
| 8903 | - | snprintf(dummy_name, 32, "f%d", fieldno); | - |
| 8904 | - | return dummy_name; | - |
| 8905 | - | } | - |
| 8906 | - | Assert(dpns->plan && (IsA(dpns->plan, CteScan) || | - |
| 8907 | - | IsA(dpns->plan, WorkTableScan))); | - |
| 8908 | - | - | |
| 8909 | - | tle = get_tle_by_resno(dpns->inner_tlist, attnum); | - |
| 8910 | - | if (!tle) | - |
| 8911 | - | elog(ERROR, "bogus varattno for subquery var: %d", | - |
| 8912 | - | attnum); | - |
| 8913 | - | Assert(netlevelsup == 0); | - |
| 8914 | - | push_child_plan(dpns, dpns->inner_plan, &save_dpns); | - |
| 8915 | - | - | |
| 8916 | - | result = get_name_for_var_field((Var *) tle->expr, fieldno, | - |
| 8917 | - | levelsup, context); | - |
| 8918 | - | - | |
| 8919 | - | pop_child_plan(dpns, &save_dpns); | - |
| 8920 | - | return result; | - |
| 8921 | - | } | - |
| 8922 | - | } | - |
| 8923 | - | break; | - |
| 8924 | - | case RTE_GROUP: | - |
| 8925 | - | - | |
| 8926 | - | /* | - |
| 8927 | - | * We couldn't get here: any Vars that reference the RTE_GROUP RTE | - |
| 8928 | - | * should have been replaced with the underlying grouping | - |
| 8929 | - | * expressions. | - |
| 8930 | - | */ | - |
| 8931 | - | break; | - |
| 8932 | - | } | - |
| 8933 | - | - | |
| 8934 | - | /* | - |
| 8935 | - | * We now have an expression we can't expand any more, so see if | - |
| 8936 | - | * get_expr_result_tupdesc() can do anything with it. | - |
| 8937 | - | */ | - |
| 8938 | - | tupleDesc = get_expr_result_tupdesc(expr, false); | - |
| 8939 | - | /* Got the tupdesc, so we can extract the field name */ | - |
| 8940 | - | Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); | - |
| 8941 | - | return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname); | - |
| 8942 | - | } | - |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 9758 | - | get_rule_expr(Node *node, deparse_context *context, | - |
| 9759 | - | bool showimplicit) | - |
| 9760 | - | { | - |
| 9761 | - | StringInfo buf = context->buf; | - |
| 9762 | - | - | |
| 9763 | - | if (node == NULL) | - |
| 9764 | - | return; | - |
| 9765 | - | - | |
| 9766 | - | /* Guard against excessively long or deeply-nested queries */ | - |
| 9767 | - | CHECK_FOR_INTERRUPTS(); | - |
| 9768 | - | check_stack_depth(); | - |
| 9769 | - | - | |
| 9770 | - | /* | - |
| 9771 | - | * Each level of get_rule_expr must emit an indivisible term | - |
| 9772 | - | * (parenthesized if necessary) to ensure result is reparsed into the same | - |
| 9773 | - | * expression tree. The only exception is that when the input is a List, | - |
| 9774 | - | * we emit the component items comma-separated with no surrounding | - |
| 9775 | - | * decoration; this is convenient for most callers. | - |
| 9776 | - | */ | - |
| 9777 | - | switch (nodeTag(node)) | - |
| 9778 | - | { | - |
| 9779 | - | case T_Var: | - |
| 9780 | - | (void) get_variable((Var *) node, 0, false, context); | - |
| 9781 | - | break; | - |
| 9782 | - | - | |
| 9783 | - | case T_Const: | - |
| 9784 | - | get_const_expr((Const *) node, context, 0); | - |
| 9785 | - | break; | - |
| 9786 | - | - | |
| 9787 | - | case T_Param: | - |
| 9788 | - | get_parameter((Param *) node, context); | - |
| 9789 | - | break; | - |
| 9790 | - | - | |
| 9791 | - | case T_Aggref: | - |
| 9792 | - | get_agg_expr((Aggref *) node, context, (Aggref *) node); | - |
| 9793 | - | break; | - |
| 9794 | - | - | |
| 9795 | - | case T_GroupingFunc: | - |
| 9796 | - | { | - |
| 9797 | - | GroupingFunc *gexpr = (GroupingFunc *) node; | - |
| 9798 | - | - | |
| 9799 | - | appendStringInfoString(buf, "GROUPING("); | - |
| 9800 | - | get_rule_expr((Node *) gexpr->args, context, true); | - |
| 9801 | - | appendStringInfoChar(buf, ')'); | - |
| 9802 | - | } | - |
| 9803 | - | break; | - |
| 9804 | - | - | |
| 9805 | - | case T_WindowFunc: | - |
| 9806 | - | get_windowfunc_expr((WindowFunc *) node, context); | - |
| 9807 | - | break; | - |
| 9808 | - | - | |
| 9809 | - | case T_MergeSupportFunc: | - |
| 9810 | - | appendStringInfoString(buf, "MERGE_ACTION()"); | - |
| 9811 | - | break; | - |
| 9812 | - | - | |
| 9813 | - | case T_SubscriptingRef: | - |
| 9814 | - | { | - |
| 9815 | - | SubscriptingRef *sbsref = (SubscriptingRef *) node; | - |
| 9816 | - | bool need_parens; | - |
| 9817 | - | - | |
| 9818 | - | /* | - |
| 9819 | - | * If the argument is a CaseTestExpr, we must be inside a | - |
| 9820 | - | * FieldStore, ie, we are assigning to an element of an array | - |
| 9821 | - | * within a composite column. Since we already punted on | - |
| 9822 | - | * displaying the FieldStore's target information, just punt | - |
| 9823 | - | * here too, and display only the assignment source | - |
| 9824 | - | * expression. | - |
| 9825 | - | */ | - |
| 9826 | - | if (IsA(sbsref->refexpr, CaseTestExpr)) | - |
| 9827 | - | { | - |
| 9828 | - | Assert(sbsref->refassgnexpr); | - |
| 9829 | - | get_rule_expr((Node *) sbsref->refassgnexpr, | - |
| 9830 | - | context, showimplicit); | - |
| 9831 | - | break; | - |
| 9832 | - | } | - |
| 9833 | - | - | |
| 9834 | - | /* | - |
| 9835 | - | * Parenthesize the argument unless it's a simple Var or a | - |
| 9836 | - | * FieldSelect. (In particular, if it's another | - |
| 9837 | - | * SubscriptingRef, we *must* parenthesize to avoid | - |
| 9838 | - | * confusion.) | - |
| 9839 | - | */ | - |
| 9840 | - | need_parens = !IsA(sbsref->refexpr, Var) && | - |
| 9841 | - | !IsA(sbsref->refexpr, FieldSelect); | - |
| 9842 | - | if (need_parens) | - |
| 9843 | - | appendStringInfoChar(buf, '('); | - |
| 9844 | - | get_rule_expr((Node *) sbsref->refexpr, context, showimplicit); | - |
| 9845 | - | if (need_parens) | - |
| 9846 | - | appendStringInfoChar(buf, ')'); | - |
| 9847 | - | - | |
| 9848 | - | /* | - |
| 9849 | - | * If there's a refassgnexpr, we want to print the node in the | - |
| 9850 | - | * format "container[subscripts] := refassgnexpr". This is | - |
| 9851 | - | * not legal SQL, so decompilation of INSERT or UPDATE | - |
| 9852 | - | * statements should always use processIndirection as part of | - |
| 9853 | - | * the statement-level syntax. We should only see this when | - |
| 9854 | - | * EXPLAIN tries to print the targetlist of a plan resulting | - |
| 9855 | - | * from such a statement. | - |
| 9856 | - | */ | - |
| 9857 | - | if (sbsref->refassgnexpr) | - |
| 9858 | - | { | - |
| 9859 | - | Node *refassgnexpr; | - |
| 9860 | - | - | |
| 9861 | - | /* | - |
| 9862 | - | * Use processIndirection to print this node's subscripts | - |
| 9863 | - | * as well as any additional field selections or | - |
| 9864 | - | * subscripting in immediate descendants. It returns the | - |
| 9865 | - | * RHS expr that is actually being "assigned". | - |
| 9866 | - | */ | - |
| 9867 | - | refassgnexpr = processIndirection(node, context); | - |
| 9868 | - | appendStringInfoString(buf, " := "); | - |
| 9869 | - | get_rule_expr(refassgnexpr, context, showimplicit); | - |
| 9870 | - | } | - |
| 9871 | - | else | - |
| 9872 | - | { | - |
| 9873 | - | /* Just an ordinary container fetch, so print subscripts */ | - |
| 9874 | - | printSubscripts(sbsref, context); | - |
| 9875 | - | } | - |
| 9876 | - | } | - |
| 9877 | - | break; | - |
| 9878 | - | - | |
| 9879 | - | case T_FuncExpr: | - |
| 9880 | - | get_func_expr((FuncExpr *) node, context, showimplicit); | - |
| 9881 | - | break; | - |
| 9882 | - | - | |
| 9883 | - | case T_NamedArgExpr: | - |
| 9884 | - | { | - |
| 9885 | - | NamedArgExpr *na = (NamedArgExpr *) node; | - |
| 9886 | - | - | |
| 9887 | - | appendStringInfo(buf, "%s => ", quote_identifier(na->name)); | - |
| 9888 | - | get_rule_expr((Node *) na->arg, context, showimplicit); | - |
| 9889 | - | } | - |
| 9890 | - | break; | - |
| 9891 | - | - | |
| 9892 | - | case T_OpExpr: | - |
| 9893 | - | get_oper_expr((OpExpr *) node, context); | - |
| 9894 | - | break; | - |
| 9895 | - | - | |
| 9896 | - | case T_DistinctExpr: | - |
| 9897 | - | { | - |
| 9898 | - | DistinctExpr *expr = (DistinctExpr *) node; | - |
| 9899 | - | List *args = expr->args; | - |
| 9900 | - | Node *arg1 = (Node *) linitial(args); | - |
| 9901 | - | Node *arg2 = (Node *) lsecond(args); | - |
| 9902 | - | - | |
| 9903 | - | if (!PRETTY_PAREN(context)) | - |
| 9904 | - | appendStringInfoChar(buf, '('); | - |
| 9905 | - | get_rule_expr_paren(arg1, context, true, node); | - |
| 9906 | - | appendStringInfoString(buf, " IS DISTINCT FROM "); | - |
| 9907 | - | get_rule_expr_paren(arg2, context, true, node); | - |
| 9908 | - | if (!PRETTY_PAREN(context)) | - |
| 9909 | - | appendStringInfoChar(buf, ')'); | - |
| 9910 | - | } | - |
| 9911 | - | break; | - |
| 9912 | - | - | |
| 9913 | - | case T_NullIfExpr: | - |
| 9914 | - | { | - |
| 9915 | - | NullIfExpr *nullifexpr = (NullIfExpr *) node; | - |
| 9916 | - | - | |
| 9917 | - | appendStringInfoString(buf, "NULLIF("); | - |
| 9918 | - | get_rule_expr((Node *) nullifexpr->args, context, true); | - |
| 9919 | - | appendStringInfoChar(buf, ')'); | - |
| 9920 | - | } | - |
| 9921 | - | break; | - |
| 9922 | - | - | |
| 9923 | - | case T_ScalarArrayOpExpr: | - |
| 9924 | - | { | - |
| 9925 | - | ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; | - |
| 9926 | - | List *args = expr->args; | - |
| 9927 | - | Node *arg1 = (Node *) linitial(args); | - |
| 9928 | - | Node *arg2 = (Node *) lsecond(args); | - |
| 9929 | - | - | |
| 9930 | - | if (!PRETTY_PAREN(context)) | - |
| 9931 | - | appendStringInfoChar(buf, '('); | - |
| 9932 | - | get_rule_expr_paren(arg1, context, true, node); | - |
| 9933 | - | appendStringInfo(buf, " %s %s (", | - |
| 9934 | - | generate_operator_name(expr->opno, | - |
| 9935 | - | exprType(arg1), | - |
| 9936 | - | get_base_element_type(exprType(arg2))), | - |
| 9937 | - | expr->useOr ? "ANY" : "ALL"); | - |
| 9938 | - | get_rule_expr_paren(arg2, context, true, node); | - |
| 9939 | - | - | |
| 9940 | - | /* | - |
| 9941 | - | * There's inherent ambiguity in "x op ANY/ALL (y)" when y is | - |
| 9942 | - | * a bare sub-SELECT. Since we're here, the sub-SELECT must | - |
| 9943 | - | * be meant as a scalar sub-SELECT yielding an array value to | - |
| 9944 | - | * be used in ScalarArrayOpExpr; but the grammar will | - |
| 9945 | - | * preferentially interpret such a construct as an ANY/ALL | - |
| 9946 | - | * SubLink. To prevent misparsing the output that way, insert | - |
| 9947 | - | * a dummy coercion (which will be stripped by parse analysis, | - |
| 9948 | - | * so no inefficiency is added in dump and reload). This is | - |
| 9949 | - | * indeed most likely what the user wrote to get the construct | - |
| 9950 | - | * accepted in the first place. | - |
| 9951 | - | */ | - |
| 9952 | - | if (IsA(arg2, SubLink) && | - |
| 9953 | - | ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK) | - |
| 9954 | - | appendStringInfo(buf, "::%s", | - |
| 9955 | - | format_type_with_typemod(exprType(arg2), | - |
| 9956 | - | exprTypmod(arg2))); | - |
| 9957 | - | appendStringInfoChar(buf, ')'); | - |
| 9958 | - | if (!PRETTY_PAREN(context)) | - |
| 9959 | - | appendStringInfoChar(buf, ')'); | - |
| 9960 | - | } | - |
| 9961 | - | break; | - |
| 9962 | - | - | |
| 9963 | - | case T_BoolExpr: | - |
| 9964 | - | { | - |
| 9965 | - | BoolExpr *expr = (BoolExpr *) node; | - |
| 9966 | - | Node *first_arg = linitial(expr->args); | - |
| 9967 | - | ListCell *arg; | - |
| 9968 | - | - | |
| 9969 | - | switch (expr->boolop) | - |
| 9970 | - | { | - |
| 9971 | - | case AND_EXPR: | - |
| 9972 | - | if (!PRETTY_PAREN(context)) | - |
| 9973 | - | appendStringInfoChar(buf, '('); | - |
| 9974 | - | get_rule_expr_paren(first_arg, context, | - |
| 9975 | - | false, node); | - |
| 9976 | - | for_each_from(arg, expr->args, 1) | - |
| 9977 | - | { | - |
| 9978 | - | appendStringInfoString(buf, " AND "); | - |
| 9979 | - | get_rule_expr_paren((Node *) lfirst(arg), context, | - |
| 9980 | - | false, node); | - |
| 9981 | - | } | - |
| 9982 | - | if (!PRETTY_PAREN(context)) | - |
| 9983 | - | appendStringInfoChar(buf, ')'); | - |
| 9984 | - | break; | - |
| 9985 | - | - | |
| 9986 | - | case OR_EXPR: | - |
| 9987 | - | if (!PRETTY_PAREN(context)) | - |
| 9988 | - | appendStringInfoChar(buf, '('); | - |
| 9989 | - | get_rule_expr_paren(first_arg, context, | - |
| 9990 | - | false, node); | - |
| 9991 | - | for_each_from(arg, expr->args, 1) | - |
| 9992 | - | { | - |
| 9993 | - | appendStringInfoString(buf, " OR "); | - |
| 9994 | - | get_rule_expr_paren((Node *) lfirst(arg), context, | - |
| 9995 | - | false, node); | - |
| 9996 | - | } | - |
| 9997 | - | if (!PRETTY_PAREN(context)) | - |
| 9998 | - | appendStringInfoChar(buf, ')'); | - |
| 9999 | - | break; | - |
| 10000 | - | - | |
| 10001 | - | case NOT_EXPR: | - |
| 10002 | - | if (!PRETTY_PAREN(context)) | - |
| 10003 | - | appendStringInfoChar(buf, '('); | - |
| 10004 | - | appendStringInfoString(buf, "NOT "); | - |
| 10005 | - | get_rule_expr_paren(first_arg, context, | - |
| 10006 | - | false, node); | - |
| 10007 | - | if (!PRETTY_PAREN(context)) | - |
| 10008 | - | appendStringInfoChar(buf, ')'); | - |
| 10009 | - | break; | - |
| 10010 | - | - | |
| 10011 | - | default: | - |
| 10012 | - | elog(ERROR, "unrecognized boolop: %d", | - |
| 10013 | - | (int) expr->boolop); | - |
| 10014 | - | } | - |
| 10015 | - | } | - |
| 10016 | - | break; | - |
| 10017 | - | - | |
| 10018 | - | case T_SubLink: | - |
| 10019 | - | get_sublink_expr((SubLink *) node, context); | - |
| 10020 | - | break; | - |
| 10021 | - | - | |
| 10022 | - | case T_SubPlan: | - |
| 10023 | - | { | - |
| 10024 | - | SubPlan *subplan = (SubPlan *) node; | - |
| 10025 | - | - | |
| 10026 | - | /* | - |
| 10027 | - | * We cannot see an already-planned subplan in rule deparsing, | - |
| 10028 | - | * only while EXPLAINing a query plan. We don't try to | - |
| 10029 | - | * reconstruct the original SQL, just reference the subplan | - |
| 10030 | - | * that appears elsewhere in EXPLAIN's result. It does seem | - |
| 10031 | - | * useful to show the subLinkType and testexpr (if any), and | - |
| 10032 | - | * we also note whether the subplan will be hashed. | - |
| 10033 | - | */ | - |
| 10034 | - | switch (subplan->subLinkType) | - |
| 10035 | - | { | - |
| 10036 | - | case EXISTS_SUBLINK: | - |
| 10037 | - | appendStringInfoString(buf, "EXISTS("); | - |
| 10038 | - | Assert(subplan->testexpr == NULL); | - |
| 10039 | - | break; | - |
| 10040 | - | case ALL_SUBLINK: | - |
| 10041 | - | appendStringInfoString(buf, "(ALL "); | - |
| 10042 | - | Assert(subplan->testexpr != NULL); | - |
| 10043 | - | break; | - |
| 10044 | - | case ANY_SUBLINK: | - |
| 10045 | - | appendStringInfoString(buf, "(ANY "); | - |
| 10046 | - | Assert(subplan->testexpr != NULL); | - |
| 10047 | - | break; | - |
| 10048 | - | case ROWCOMPARE_SUBLINK: | - |
| 10049 | - | /* Parenthesizing the testexpr seems sufficient */ | - |
| 10050 | - | appendStringInfoChar(buf, '('); | - |
| 10051 | - | Assert(subplan->testexpr != NULL); | - |
| 10052 | - | break; | - |
| 10053 | - | case EXPR_SUBLINK: | - |
| 10054 | - | /* No need to decorate these subplan references */ | - |
| 10055 | - | appendStringInfoChar(buf, '('); | - |
| 10056 | - | Assert(subplan->testexpr == NULL); | - |
| 10057 | - | break; | - |
| 10058 | - | case MULTIEXPR_SUBLINK: | - |
| 10059 | - | /* MULTIEXPR isn't executed in the normal way */ | - |
| 10060 | - | appendStringInfoString(buf, "(rescan "); | - |
| 10061 | - | Assert(subplan->testexpr == NULL); | - |
| 10062 | - | break; | - |
| 10063 | - | case ARRAY_SUBLINK: | - |
| 10064 | - | appendStringInfoString(buf, "ARRAY("); | - |
| 10065 | - | Assert(subplan->testexpr == NULL); | - |
| 10066 | - | break; | - |
| 10067 | - | case CTE_SUBLINK: | - |
| 10068 | - | /* This case is unreachable within expressions */ | - |
| 10069 | - | appendStringInfoString(buf, "CTE("); | - |
| 10070 | - | Assert(subplan->testexpr == NULL); | - |
| 10071 | - | break; | - |
| 10072 | - | } | - |
| 10073 | - | - | |
| 10074 | - | if (subplan->testexpr != NULL) | - |
| 10075 | - | { | - |
| 10076 | - | deparse_namespace *dpns; | - |
| 10077 | - | - | |
| 10078 | - | /* | - |
| 10079 | - | * Push SubPlan into ancestors list while deparsing | - |
| 10080 | - | * testexpr, so that we can handle PARAM_EXEC references | - |
| 10081 | - | * to the SubPlan's paramIds. (This makes it look like | - |
| 10082 | - | * the SubPlan is an "ancestor" of the current plan node, | - |
| 10083 | - | * which is a little weird, but it does no harm.) In this | - |
| 10084 | - | * path, we don't need to mention the SubPlan explicitly, | - |
| 10085 | - | * because the referencing Params will show its existence. | - |
| 10086 | - | */ | - |
| 10087 | - | dpns = (deparse_namespace *) linitial(context->namespaces); | - |
| 10088 | - | dpns->ancestors = lcons(subplan, dpns->ancestors); | - |
| 10089 | - | - | |
| 10090 | - | get_rule_expr(subplan->testexpr, context, showimplicit); | - |
| 10091 | - | appendStringInfoChar(buf, ')'); | - |
| 10092 | - | - | |
| 10093 | - | dpns->ancestors = list_delete_first(dpns->ancestors); | - |
| 10094 | - | } | - |
| 10095 | - | else | - |
| 10096 | - | { | - |
| 10097 | - | const char *nameprefix; | - |
| 10098 | - | - | |
| 10099 | - | /* No referencing Params, so show the SubPlan's name */ | - |
| 10100 | - | if (subplan->isInitPlan) | - |
| 10101 | - | nameprefix = "InitPlan "; | - |
| 10102 | - | else | - |
| 10103 | - | nameprefix = "SubPlan "; | - |
| 10104 | - | if (subplan->useHashTable) | - |
| 10105 | - | appendStringInfo(buf, "hashed %s%s)", | - |
| 10106 | - | nameprefix, subplan->plan_name); | - |
| 10107 | - | else | - |
| 10108 | - | appendStringInfo(buf, "%s%s)", | - |
| 10109 | - | nameprefix, subplan->plan_name); | - |
| 10110 | - | } | - |
| 10111 | - | } | - |
| 10112 | - | break; | - |
| 10113 | - | - | |
| 10114 | - | case T_AlternativeSubPlan: | - |
| 10115 | - | { | - |
| 10116 | - | AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; | - |
| 10117 | - | ListCell *lc; | - |
| 10118 | - | - | |
| 10119 | - | /* | - |
| 10120 | - | * This case cannot be reached in normal usage, since no | - |
| 10121 | - | * AlternativeSubPlan can appear either in parsetrees or | - |
| 10122 | - | * finished plan trees. We keep it just in case somebody | - |
| 10123 | - | * wants to use this code to print planner data structures. | - |
| 10124 | - | */ | - |
| 10125 | - | appendStringInfoString(buf, "(alternatives: "); | - |
| 10126 | - | foreach(lc, asplan->subplans) | - |
| 10127 | - | { | - |
| 10128 | - | SubPlan *splan = lfirst_node(SubPlan, lc); | - |
| 10129 | - | const char *nameprefix; | - |
| 10130 | - | - | |
| 10131 | - | if (splan->isInitPlan) | - |
| 10132 | - | nameprefix = "InitPlan "; | - |
| 10133 | - | else | - |
| 10134 | - | nameprefix = "SubPlan "; | - |
| 10135 | - | if (splan->useHashTable) | - |
| 10136 | - | appendStringInfo(buf, "hashed %s%s", nameprefix, | - |
| 10137 | - | splan->plan_name); | - |
| 10138 | - | else | - |
| 10139 | - | appendStringInfo(buf, "%s%s", nameprefix, | - |
| 10140 | - | splan->plan_name); | - |
| 10141 | - | if (lnext(asplan->subplans, lc)) | - |
| 10142 | - | appendStringInfoString(buf, " or "); | - |
| 10143 | - | } | - |
| 10144 | - | appendStringInfoChar(buf, ')'); | - |
| 10145 | - | } | - |
| 10146 | - | break; | - |
| 10147 | - | - | |
| 10148 | - | case T_FieldSelect: | - |
| 10149 | - | { | - |
| 10150 | - | FieldSelect *fselect = (FieldSelect *) node; | - |
| 10151 | - | Node *arg = (Node *) fselect->arg; | - |
| 10152 | - | int fno = fselect->fieldnum; | - |
| 10153 | - | const char *fieldname; | - |
| 10154 | - | bool need_parens; | - |
| 10155 | - | - | |
| 10156 | - | /* | - |
| 10157 | - | * Parenthesize the argument unless it's an SubscriptingRef or | - |
| 10158 | - | * another FieldSelect. Note in particular that it would be | - |
| 10159 | - | * WRONG to not parenthesize a Var argument; simplicity is not | - |
| 10160 | - | * the issue here, having the right number of names is. | - |
| 10161 | - | */ | - |
| 10162 | - | need_parens = !IsA(arg, SubscriptingRef) && | - |
| 10163 | - | !IsA(arg, FieldSelect); | - |
| 10164 | - | if (need_parens) | - |
| 10165 | - | appendStringInfoChar(buf, '('); | - |
| 10166 | - | get_rule_expr(arg, context, true); | - |
| 10167 | - | if (need_parens) | - |
| 10168 | - | appendStringInfoChar(buf, ')'); | - |
| 10169 | - | - | |
| 10170 | - | /* | - |
| 10171 | - | * Get and print the field name. | - |
| 10172 | - | */ | - |
| 10173 | - | fieldname = get_name_for_var_field((Var *) arg, fno, | - |
| 10174 | - | 0, context); | - |
| 10175 | - | appendStringInfo(buf, ".%s", quote_identifier(fieldname)); | - |
| 10176 | - | } | - |
| 10177 | - | break; | - |
| 10178 | - | - | |
| 10179 | - | case T_FieldStore: | - |
| 10180 | - | { | - |
| 10181 | - | FieldStore *fstore = (FieldStore *) node; | - |
| 10182 | - | bool need_parens; | - |
| 10183 | - | - | |
| 10184 | - | /* | - |
| 10185 | - | * There is no good way to represent a FieldStore as real SQL, | - |
| 10186 | - | * so decompilation of INSERT or UPDATE statements should | - |
| 10187 | - | * always use processIndirection as part of the | - |
| 10188 | - | * statement-level syntax. We should only get here when | - |
| 10189 | - | * EXPLAIN tries to print the targetlist of a plan resulting | - |
| 10190 | - | * from such a statement. The plan case is even harder than | - |
| 10191 | - | * ordinary rules would be, because the planner tries to | - |
| 10192 | - | * collapse multiple assignments to the same field or subfield | - |
| 10193 | - | * into one FieldStore; so we can see a list of target fields | - |
| 10194 | - | * not just one, and the arguments could be FieldStores | - |
| 10195 | - | * themselves. We don't bother to try to print the target | - |
| 10196 | - | * field names; we just print the source arguments, with a | - |
| 10197 | - | * ROW() around them if there's more than one. This isn't | - |
| 10198 | - | * terribly complete, but it's probably good enough for | - |
| 10199 | - | * EXPLAIN's purposes; especially since anything more would be | - |
| 10200 | - | * either hopelessly confusing or an even poorer | - |
| 10201 | - | * representation of what the plan is actually doing. | - |
| 10202 | - | */ | - |
| 10203 | - | need_parens = (list_length(fstore->newvals) != 1); | - |
| 10204 | - | if (need_parens) | - |
| 10205 | - | appendStringInfoString(buf, "ROW("); | - |
| 10206 | - | get_rule_expr((Node *) fstore->newvals, context, showimplicit); | - |
| 10207 | - | if (need_parens) | - |
| 10208 | - | appendStringInfoChar(buf, ')'); | - |
| 10209 | - | } | - |
| 10210 | - | break; | - |
| 10211 | - | - | |
| 10212 | - | case T_RelabelType: | - |
| 10213 | - | { | - |
| 10214 | - | RelabelType *relabel = (RelabelType *) node; | - |
| 10215 | - | Node *arg = (Node *) relabel->arg; | - |
| 10216 | - | - | |
| 10217 | - | if (relabel->relabelformat == COERCE_IMPLICIT_CAST && | - |
| 10218 | - | !showimplicit) | - |
| 10219 | - | { | - |
| 10220 | - | /* don't show the implicit cast */ | - |
| 10221 | - | get_rule_expr_paren(arg, context, false, node); | - |
| 10222 | - | } | - |
| 10223 | - | else | - |
| 10224 | - | { | - |
| 10225 | - | get_coercion_expr(arg, context, | - |
| 10226 | - | relabel->resulttype, | - |
| 10227 | - | relabel->resulttypmod, | - |
| 10228 | - | node); | - |
| 10229 | - | } | - |
| 10230 | - | } | - |
| 10231 | - | break; | - |
| 10232 | - | - | |
| 10233 | - | case T_CoerceViaIO: | - |
| 10234 | - | { | - |
| 10235 | - | CoerceViaIO *iocoerce = (CoerceViaIO *) node; | - |
| 10236 | - | Node *arg = (Node *) iocoerce->arg; | - |
| 10237 | - | - | |
| 10238 | - | if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST && | - |
| 10239 | - | !showimplicit) | - |
| 10240 | - | { | - |
| 10241 | - | /* don't show the implicit cast */ | - |
| 10242 | - | get_rule_expr_paren(arg, context, false, node); | - |
| 10243 | - | } | - |
| 10244 | - | else | - |
| 10245 | - | { | - |
| 10246 | - | get_coercion_expr(arg, context, | - |
| 10247 | - | iocoerce->resulttype, | - |
| 10248 | - | -1, | - |
| 10249 | - | node); | - |
| 10250 | - | } | - |
| 10251 | - | } | - |
| 10252 | - | break; | - |
| 10253 | - | - | |
| 10254 | - | case T_ArrayCoerceExpr: | - |
| 10255 | - | { | - |
| 10256 | - | ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; | - |
| 10257 | - | Node *arg = (Node *) acoerce->arg; | - |
| 10258 | - | - | |
| 10259 | - | if (acoerce->coerceformat == COERCE_IMPLICIT_CAST && | - |
| 10260 | - | !showimplicit) | - |
| 10261 | - | { | - |
| 10262 | - | /* don't show the implicit cast */ | - |
| 10263 | - | get_rule_expr_paren(arg, context, false, node); | - |
| 10264 | - | } | - |
| 10265 | - | else | - |
| 10266 | - | { | - |
| 10267 | - | get_coercion_expr(arg, context, | - |
| 10268 | - | acoerce->resulttype, | - |
| 10269 | - | acoerce->resulttypmod, | - |
| 10270 | - | node); | - |
| 10271 | - | } | - |
| 10272 | - | } | - |
| 10273 | - | break; | - |
| 10274 | - | - | |
| 10275 | - | case T_ConvertRowtypeExpr: | - |
| 10276 | - | { | - |
| 10277 | - | ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; | - |
| 10278 | - | Node *arg = (Node *) convert->arg; | - |
| 10279 | - | - | |
| 10280 | - | if (convert->convertformat == COERCE_IMPLICIT_CAST && | - |
| 10281 | - | !showimplicit) | - |
| 10282 | - | { | - |
| 10283 | - | /* don't show the implicit cast */ | - |
| 10284 | - | get_rule_expr_paren(arg, context, false, node); | - |
| 10285 | - | } | - |
| 10286 | - | else | - |
| 10287 | - | { | - |
| 10288 | - | get_coercion_expr(arg, context, | - |
| 10289 | - | convert->resulttype, -1, | - |
| 10290 | - | node); | - |
| 10291 | - | } | - |
| 10292 | - | } | - |
| 10293 | - | break; | - |
| 10294 | - | - | |
| 10295 | - | case T_CollateExpr: | - |
| 10296 | - | { | - |
| 10297 | - | CollateExpr *collate = (CollateExpr *) node; | - |
| 10298 | - | Node *arg = (Node *) collate->arg; | - |
| 10299 | - | - | |
| 10300 | - | if (!PRETTY_PAREN(context)) | - |
| 10301 | - | appendStringInfoChar(buf, '('); | - |
| 10302 | - | get_rule_expr_paren(arg, context, showimplicit, node); | - |
| 10303 | - | appendStringInfo(buf, " COLLATE %s", | - |
| 10304 | - | generate_collation_name(collate->collOid)); | - |
| 10305 | - | if (!PRETTY_PAREN(context)) | - |
| 10306 | - | appendStringInfoChar(buf, ')'); | - |
| 10307 | - | } | - |
| 10308 | - | break; | - |
| 10309 | - | - | |
| 10310 | - | case T_CaseExpr: | - |
| 10311 | - | { | - |
| 10312 | - | CaseExpr *caseexpr = (CaseExpr *) node; | - |
| 10313 | - | ListCell *temp; | - |
| 10314 | - | - | |
| 10315 | - | appendContextKeyword(context, "CASE", | - |
| 10316 | - | 0, PRETTYINDENT_VAR, 0); | - |
| 10317 | - | if (caseexpr->arg) | - |
| 10318 | - | { | - |
| 10319 | - | appendStringInfoChar(buf, ' '); | - |
| 10320 | - | get_rule_expr((Node *) caseexpr->arg, context, true); | - |
| 10321 | - | } | - |
| 10322 | - | foreach(temp, caseexpr->args) | - |
| 10323 | - | { | - |
| 10324 | - | CaseWhen *when = (CaseWhen *) lfirst(temp); | - |
| 10325 | - | Node *w = (Node *) when->expr; | - |
| 10326 | - | - | |
| 10327 | - | if (caseexpr->arg) | - |
| 10328 | - | { | - |
| 10329 | - | /* | - |
| 10330 | - | * The parser should have produced WHEN clauses of the | - |
| 10331 | - | * form "CaseTestExpr = RHS", possibly with an | - |
| 10332 | - | * implicit coercion inserted above the CaseTestExpr. | - |
| 10333 | - | * For accurate decompilation of rules it's essential | - |
| 10334 | - | * that we show just the RHS. However in an | - |
| 10335 | - | * expression that's been through the optimizer, the | - |
| 10336 | - | * WHEN clause could be almost anything (since the | - |
| 10337 | - | * equality operator could have been expanded into an | - |
| 10338 | - | * inline function). If we don't recognize the form | - |
| 10339 | - | * of the WHEN clause, just punt and display it as-is. | - |
| 10340 | - | */ | - |
| 10341 | - | if (IsA(w, OpExpr)) | - |
| 10342 | - | { | - |
| 10343 | - | List *args = ((OpExpr *) w)->args; | - |
| 10344 | - | - | |
| 10345 | - | if (list_length(args) == 2 && | - |
| 10346 | - | IsA(strip_implicit_coercions(linitial(args)), | - |
| 10347 | - | CaseTestExpr)) | - |
| 10348 | - | w = (Node *) lsecond(args); | - |
| 10349 | - | } | - |
| 10350 | - | } | - |
| 10351 | - | - | |
| 10352 | - | if (!PRETTY_INDENT(context)) | - |
| 10353 | - | appendStringInfoChar(buf, ' '); | - |
| 10354 | - | appendContextKeyword(context, "WHEN ", | - |
| 10355 | - | 0, 0, 0); | - |
| 10356 | - | get_rule_expr(w, context, false); | - |
| 10357 | - | appendStringInfoString(buf, " THEN "); | - |
| 10358 | - | get_rule_expr((Node *) when->result, context, true); | - |
| 10359 | - | } | - |
| 10360 | - | if (!PRETTY_INDENT(context)) | - |
| 10361 | - | appendStringInfoChar(buf, ' '); | - |
| 10362 | - | appendContextKeyword(context, "ELSE ", | - |
| 10363 | - | 0, 0, 0); | - |
| 10364 | - | get_rule_expr((Node *) caseexpr->defresult, context, true); | - |
| 10365 | - | if (!PRETTY_INDENT(context)) | - |
| 10366 | - | appendStringInfoChar(buf, ' '); | - |
| 10367 | - | appendContextKeyword(context, "END", | - |
| 10368 | - | -PRETTYINDENT_VAR, 0, 0); | - |
| 10369 | - | } | - |
| 10370 | - | break; | - |
| 10371 | - | - | |
| 10372 | - | case T_CaseTestExpr: | - |
| 10373 | - | { | - |
| 10374 | - | /* | - |
| 10375 | - | * Normally we should never get here, since for expressions | - |
| 10376 | - | * that can contain this node type we attempt to avoid | - |
| 10377 | - | * recursing to it. But in an optimized expression we might | - |
| 10378 | - | * be unable to avoid that (see comments for CaseExpr). If we | - |
| 10379 | - | * do see one, print it as CASE_TEST_EXPR. | - |
| 10380 | - | */ | - |
| 10381 | - | appendStringInfoString(buf, "CASE_TEST_EXPR"); | - |
| 10382 | - | } | - |
| 10383 | - | break; | - |
| 10384 | - | - | |
| 10385 | - | case T_ArrayExpr: | - |
| 10386 | - | { | - |
| 10387 | - | ArrayExpr *arrayexpr = (ArrayExpr *) node; | - |
| 10388 | - | - | |
| 10389 | - | appendStringInfoString(buf, "ARRAY["); | - |
| 10390 | - | get_rule_expr((Node *) arrayexpr->elements, context, true); | - |
| 10391 | - | appendStringInfoChar(buf, ']'); | - |
| 10392 | - | - | |
| 10393 | - | /* | - |
| 10394 | - | * If the array isn't empty, we assume its elements are | - |
| 10395 | - | * coerced to the desired type. If it's empty, though, we | - |
| 10396 | - | * need an explicit coercion to the array type. | - |
| 10397 | - | */ | - |
| 10398 | - | if (arrayexpr->elements == NIL) | - |
| 10399 | - | appendStringInfo(buf, "::%s", | - |
| 10400 | - | format_type_with_typemod(arrayexpr->array_typeid, -1)); | - |
| 10401 | - | } | - |
| 10402 | - | break; | - |
| 10403 | - | - | |
| 10404 | - | case T_RowExpr: | - |
| 10405 | - | { | - |
| 10406 | - | RowExpr *rowexpr = (RowExpr *) node; | - |
| 10407 | - | TupleDesc tupdesc = NULL; | - |
| 10408 | - | ListCell *arg; | - |
| 10409 | - | int i; | - |
| 10410 | - | char *sep; | - |
| 10411 | - | - | |
| 10412 | - | /* | - |
| 10413 | - | * If it's a named type and not RECORD, we may have to skip | - |
| 10414 | - | * dropped columns and/or claim there are NULLs for added | - |
| 10415 | - | * columns. | - |
| 10416 | - | */ | - |
| 10417 | - | if (rowexpr->row_typeid != RECORDOID) | - |
| 10418 | - | { | - |
| 10419 | - | tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1); | - |
| 10420 | - | Assert(list_length(rowexpr->args) <= tupdesc->natts); | - |
| 10421 | - | } | - |
| 10422 | - | - | |
| 10423 | - | /* | - |
| 10424 | - | * SQL99 allows "ROW" to be omitted when there is more than | - |
| 10425 | - | * one column, but for simplicity we always print it. | - |
| 10426 | - | */ | - |
| 10427 | - | appendStringInfoString(buf, "ROW("); | - |
| 10428 | - | sep = ""; | - |
| 10429 | - | i = 0; | - |
| 10430 | - | foreach(arg, rowexpr->args) | - |
| 10431 | - | { | - |
| 10432 | - | Node *e = (Node *) lfirst(arg); | - |
| 10433 | - | - | |
| 10434 | - | if (tupdesc == NULL || | - |
| 10435 | - | !TupleDescCompactAttr(tupdesc, i)->attisdropped) | - |
| 10436 | - | { | - |
| 10437 | - | appendStringInfoString(buf, sep); | - |
| 10438 | - | /* Whole-row Vars need special treatment here */ | - |
| 10439 | - | get_rule_expr_toplevel(e, context, true); | - |
| 10440 | - | sep = ", "; | - |
| 10441 | - | } | - |
| 10442 | - | i++; | - |
| 10443 | - | } | - |
| 10444 | - | if (tupdesc != NULL) | - |
| 10445 | - | { | - |
| 10446 | - | while (i < tupdesc->natts) | - |
| 10447 | - | { | - |
| 10448 | - | if (!TupleDescCompactAttr(tupdesc, i)->attisdropped) | - |
| 10449 | - | { | - |
| 10450 | - | appendStringInfoString(buf, sep); | - |
| 10451 | - | appendStringInfoString(buf, "NULL"); | - |
| 10452 | - | sep = ", "; | - |
| 10453 | - | } | - |
| 10454 | - | i++; | - |
| 10455 | - | } | - |
| 10456 | - | - | |
| 10457 | - | ReleaseTupleDesc(tupdesc); | - |
| 10458 | - | } | - |
| 10459 | - | appendStringInfoChar(buf, ')'); | - |
| 10460 | - | if (rowexpr->row_format == COERCE_EXPLICIT_CAST) | - |
| 10461 | - | appendStringInfo(buf, "::%s", | - |
| 10462 | - | format_type_with_typemod(rowexpr->row_typeid, -1)); | - |
| 10463 | - | } | - |
| 10464 | - | break; | - |
| 10465 | - | - | |
| 10466 | - | case T_RowCompareExpr: | - |
| 10467 | - | { | - |
| 10468 | - | RowCompareExpr *rcexpr = (RowCompareExpr *) node; | - |
| 10469 | - | - | |
| 10470 | - | /* | - |
| 10471 | - | * SQL99 allows "ROW" to be omitted when there is more than | - |
| 10472 | - | * one column, but for simplicity we always print it. Within | - |
| 10473 | - | * a ROW expression, whole-row Vars need special treatment, so | - |
| 10474 | - | * use get_rule_list_toplevel. | - |
| 10475 | - | */ | - |
| 10476 | - | appendStringInfoString(buf, "(ROW("); | - |
| 10477 | - | get_rule_list_toplevel(rcexpr->largs, context, true); | - |
| 10478 | - | - | |
| 10479 | - | /* | - |
| 10480 | - | * We assume that the name of the first-column operator will | - |
| 10481 | - | * do for all the rest too. This is definitely open to | - |
| 10482 | - | * failure, eg if some but not all operators were renamed | - |
| 10483 | - | * since the construct was parsed, but there seems no way to | - |
| 10484 | - | * be perfect. | - |
| 10485 | - | */ | - |
| 10486 | - | appendStringInfo(buf, ") %s ROW(", | - |
| 10487 | - | generate_operator_name(linitial_oid(rcexpr->opnos), | - |
| 10488 | - | exprType(linitial(rcexpr->largs)), | - |
| 10489 | - | exprType(linitial(rcexpr->rargs)))); | - |
| 10490 | - | get_rule_list_toplevel(rcexpr->rargs, context, true); | - |
| 10491 | - | appendStringInfoString(buf, "))"); | - |
| 10492 | - | } | - |
| 10493 | - | break; | - |
| 10494 | - | - | |
| 10495 | - | case T_CoalesceExpr: | - |
| 10496 | - | { | - |
| 10497 | - | CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; | - |
| 10498 | - | - | |
| 10499 | - | appendStringInfoString(buf, "COALESCE("); | - |
| 10500 | - | get_rule_expr((Node *) coalesceexpr->args, context, true); | - |
| 10501 | - | appendStringInfoChar(buf, ')'); | - |
| 10502 | - | } | - |
| 10503 | - | break; | - |
| 10504 | - | - | |
| 10505 | - | case T_MinMaxExpr: | - |
| 10506 | - | { | - |
| 10507 | - | MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; | - |
| 10508 | - | - | |
| 10509 | - | switch (minmaxexpr->op) | - |
| 10510 | - | { | - |
| 10511 | - | case IS_GREATEST: | - |
| 10512 | - | appendStringInfoString(buf, "GREATEST("); | - |
| 10513 | - | break; | - |
| 10514 | - | case IS_LEAST: | - |
| 10515 | - | appendStringInfoString(buf, "LEAST("); | - |
| 10516 | - | break; | - |
| 10517 | - | } | - |
| 10518 | - | get_rule_expr((Node *) minmaxexpr->args, context, true); | - |
| 10519 | - | appendStringInfoChar(buf, ')'); | - |
| 10520 | - | } | - |
| 10521 | - | break; | - |
| 10522 | - | - | |
| 10523 | - | case T_SQLValueFunction: | - |
| 10524 | - | { | - |
| 10525 | - | SQLValueFunction *svf = (SQLValueFunction *) node; | - |
| 10526 | - | - | |
| 10527 | - | /* | - |
| 10528 | - | * Note: this code knows that typmod for time, timestamp, and | - |
| 10529 | - | * timestamptz just prints as integer. | - |
| 10530 | - | */ | - |
| 10531 | - | switch (svf->op) | - |
| 10532 | - | { | - |
| 10533 | - | case SVFOP_CURRENT_DATE: | - |
| 10534 | - | appendStringInfoString(buf, "CURRENT_DATE"); | - |
| 10535 | - | break; | - |
| 10536 | - | case SVFOP_CURRENT_TIME: | - |
| 10537 | - | appendStringInfoString(buf, "CURRENT_TIME"); | - |
| 10538 | - | break; | - |
| 10539 | - | case SVFOP_CURRENT_TIME_N: | - |
| 10540 | - | appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod); | - |
| 10541 | - | break; | - |
| 10542 | - | case SVFOP_CURRENT_TIMESTAMP: | - |
| 10543 | - | appendStringInfoString(buf, "CURRENT_TIMESTAMP"); | - |
| 10544 | - | break; | - |
| 10545 | - | case SVFOP_CURRENT_TIMESTAMP_N: | - |
| 10546 | - | appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)", | - |
| 10547 | - | svf->typmod); | - |
| 10548 | - | break; | - |
| 10549 | - | case SVFOP_LOCALTIME: | - |
| 10550 | - | appendStringInfoString(buf, "LOCALTIME"); | - |
| 10551 | - | break; | - |
| 10552 | - | case SVFOP_LOCALTIME_N: | - |
| 10553 | - | appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod); | - |
| 10554 | - | break; | - |
| 10555 | - | case SVFOP_LOCALTIMESTAMP: | - |
| 10556 | - | appendStringInfoString(buf, "LOCALTIMESTAMP"); | - |
| 10557 | - | break; | - |
| 10558 | - | case SVFOP_LOCALTIMESTAMP_N: | - |
| 10559 | - | appendStringInfo(buf, "LOCALTIMESTAMP(%d)", | - |
| 10560 | - | svf->typmod); | - |
| 10561 | - | break; | - |
| 10562 | - | case SVFOP_CURRENT_ROLE: | - |
| 10563 | - | appendStringInfoString(buf, "CURRENT_ROLE"); | - |
| 10564 | - | break; | - |
| 10565 | - | case SVFOP_CURRENT_USER: | - |
| 10566 | - | appendStringInfoString(buf, "CURRENT_USER"); | - |
| 10567 | - | break; | - |
| 10568 | - | case SVFOP_USER: | - |
| 10569 | - | appendStringInfoString(buf, "USER"); | - |
| 10570 | - | break; | - |
| 10571 | - | case SVFOP_SESSION_USER: | - |
| 10572 | - | appendStringInfoString(buf, "SESSION_USER"); | - |
| 10573 | - | break; | - |
| 10574 | - | case SVFOP_CURRENT_CATALOG: | - |
| 10575 | - | appendStringInfoString(buf, "CURRENT_CATALOG"); | - |
| 10576 | - | break; | - |
| 10577 | - | case SVFOP_CURRENT_SCHEMA: | - |
| 10578 | - | appendStringInfoString(buf, "CURRENT_SCHEMA"); | - |
| 10579 | - | break; | - |
| 10580 | - | } | - |
| 10581 | - | } | - |
| 10582 | - | break; | - |
| 10583 | - | - | |
| 10584 | - | case T_XmlExpr: | - |
| 10585 | - | { | - |
| 10586 | - | XmlExpr *xexpr = (XmlExpr *) node; | - |
| 10587 | - | bool needcomma = false; | - |
| 10588 | - | ListCell *arg; | - |
| 10589 | - | ListCell *narg; | - |
| 10590 | - | Const *con; | - |
| 10591 | - | - | |
| 10592 | - | switch (xexpr->op) | - |
| 10593 | - | { | - |
| 10594 | - | case IS_XMLCONCAT: | - |
| 10595 | - | appendStringInfoString(buf, "XMLCONCAT("); | - |
| 10596 | - | break; | - |
| 10597 | - | case IS_XMLELEMENT: | - |
| 10598 | - | appendStringInfoString(buf, "XMLELEMENT("); | - |
| 10599 | - | break; | - |
| 10600 | - | case IS_XMLFOREST: | - |
| 10601 | - | appendStringInfoString(buf, "XMLFOREST("); | - |
| 10602 | - | break; | - |
| 10603 | - | case IS_XMLPARSE: | - |
| 10604 | - | appendStringInfoString(buf, "XMLPARSE("); | - |
| 10605 | - | break; | - |
| 10606 | - | case IS_XMLPI: | - |
| 10607 | - | appendStringInfoString(buf, "XMLPI("); | - |
| 10608 | - | break; | - |
| 10609 | - | case IS_XMLROOT: | - |
| 10610 | - | appendStringInfoString(buf, "XMLROOT("); | - |
| 10611 | - | break; | - |
| 10612 | - | case IS_XMLSERIALIZE: | - |
| 10613 | - | appendStringInfoString(buf, "XMLSERIALIZE("); | - |
| 10614 | - | break; | - |
| 10615 | - | case IS_DOCUMENT: | - |
| 10616 | - | break; | - |
| 10617 | - | } | - |
| 10618 | - | if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE) | - |
| 10619 | - | { | - |
| 10620 | - | if (xexpr->xmloption == XMLOPTION_DOCUMENT) | - |
| 10621 | - | appendStringInfoString(buf, "DOCUMENT "); | - |
| 10622 | - | else | - |
| 10623 | - | appendStringInfoString(buf, "CONTENT "); | - |
| 10624 | - | } | - |
| 10625 | - | if (xexpr->name) | - |
| 10626 | - | { | - |
| 10627 | - | appendStringInfo(buf, "NAME %s", | - |
| 10628 | - | quote_identifier(map_xml_name_to_sql_identifier(xexpr->name))); | - |
| 10629 | - | needcomma = true; | - |
| 10630 | - | } | - |
| 10631 | - | if (xexpr->named_args) | - |
| 10632 | - | { | - |
| 10633 | - | if (xexpr->op != IS_XMLFOREST) | - |
| 10634 | - | { | - |
| 10635 | - | if (needcomma) | - |
| 10636 | - | appendStringInfoString(buf, ", "); | - |
| 10637 | - | appendStringInfoString(buf, "XMLATTRIBUTES("); | - |
| 10638 | - | needcomma = false; | - |
| 10639 | - | } | - |
| 10640 | - | forboth(arg, xexpr->named_args, narg, xexpr->arg_names) | - |
| 10641 | - | { | - |
| 10642 | - | Node *e = (Node *) lfirst(arg); | - |
| 10643 | - | char *argname = strVal(lfirst(narg)); | - |
| 10644 | - | - | |
| 10645 | - | if (needcomma) | - |
| 10646 | - | appendStringInfoString(buf, ", "); | - |
| 10647 | - | get_rule_expr(e, context, true); | - |
| 10648 | - | appendStringInfo(buf, " AS %s", | - |
| 10649 | - | quote_identifier(map_xml_name_to_sql_identifier(argname))); | - |
| 10650 | - | needcomma = true; | - |
| 10651 | - | } | - |
| 10652 | - | if (xexpr->op != IS_XMLFOREST) | - |
| 10653 | - | appendStringInfoChar(buf, ')'); | - |
| 10654 | - | } | - |
| 10655 | - | if (xexpr->args) | - |
| 10656 | - | { | - |
| 10657 | - | if (needcomma) | - |
| 10658 | - | appendStringInfoString(buf, ", "); | - |
| 10659 | - | switch (xexpr->op) | - |
| 10660 | - | { | - |
| 10661 | - | case IS_XMLCONCAT: | - |
| 10662 | - | case IS_XMLELEMENT: | - |
| 10663 | - | case IS_XMLFOREST: | - |
| 10664 | - | case IS_XMLPI: | - |
| 10665 | - | case IS_XMLSERIALIZE: | - |
| 10666 | - | /* no extra decoration needed */ | - |
| 10667 | - | get_rule_expr((Node *) xexpr->args, context, true); | - |
| 10668 | - | break; | - |
| 10669 | - | case IS_XMLPARSE: | - |
| 10670 | - | Assert(list_length(xexpr->args) == 2); | - |
| 10671 | - | - | |
| 10672 | - | get_rule_expr((Node *) linitial(xexpr->args), | - |
| 10673 | - | context, true); | - |
| 10674 | - | - | |
| 10675 | - | con = lsecond_node(Const, xexpr->args); | - |
| 10676 | - | Assert(!con->constisnull); | - |
| 10677 | - | if (DatumGetBool(con->constvalue)) | - |
| 10678 | - | appendStringInfoString(buf, | - |
| 10679 | - | " PRESERVE WHITESPACE"); | - |
| 10680 | - | else | - |
| 10681 | - | appendStringInfoString(buf, | - |
| 10682 | - | " STRIP WHITESPACE"); | - |
| 10683 | - | break; | - |
| 10684 | - | case IS_XMLROOT: | - |
| 10685 | - | Assert(list_length(xexpr->args) == 3); | - |
| 10686 | - | - | |
| 10687 | - | get_rule_expr((Node *) linitial(xexpr->args), | - |
| 10688 | - | context, true); | - |
| 10689 | - | - | |
| 10690 | - | appendStringInfoString(buf, ", VERSION "); | - |
| 10691 | - | con = (Const *) lsecond(xexpr->args); | - |
| 10692 | - | if (IsA(con, Const) && | - |
| 10693 | - | con->constisnull) | - |
| 10694 | - | appendStringInfoString(buf, "NO VALUE"); | - |
| 10695 | - | else | - |
| 10696 | - | get_rule_expr((Node *) con, context, false); | - |
| 10697 | - | - | |
| 10698 | - | con = lthird_node(Const, xexpr->args); | - |
| 10699 | - | if (con->constisnull) | - |
| 10700 | - | /* suppress STANDALONE NO VALUE */ ; | - |
| 10701 | - | else | - |
| 10702 | - | { | - |
| 10703 | - | switch (DatumGetInt32(con->constvalue)) | - |
| 10704 | - | { | - |
| 10705 | - | case XML_STANDALONE_YES: | - |
| 10706 | - | appendStringInfoString(buf, | - |
| 10707 | - | ", STANDALONE YES"); | - |
| 10708 | - | break; | - |
| 10709 | - | case XML_STANDALONE_NO: | - |
| 10710 | - | appendStringInfoString(buf, | - |
| 10711 | - | ", STANDALONE NO"); | - |
| 10712 | - | break; | - |
| 10713 | - | case XML_STANDALONE_NO_VALUE: | - |
| 10714 | - | appendStringInfoString(buf, | - |
| 10715 | - | ", STANDALONE NO VALUE"); | - |
| 10716 | - | break; | - |
| 10717 | - | default: | - |
| 10718 | - | break; | - |
| 10719 | - | } | - |
| 10720 | - | } | - |
| 10721 | - | break; | - |
| 10722 | - | case IS_DOCUMENT: | - |
| 10723 | - | get_rule_expr_paren((Node *) xexpr->args, context, false, node); | - |
| 10724 | - | break; | - |
| 10725 | - | } | - |
| 10726 | - | } | - |
| 10727 | - | if (xexpr->op == IS_XMLSERIALIZE) | - |
| 10728 | - | { | - |
| 10729 | - | appendStringInfo(buf, " AS %s", | - |
| 10730 | - | format_type_with_typemod(xexpr->type, | - |
| 10731 | - | xexpr->typmod)); | - |
| 10732 | - | if (xexpr->indent) | - |
| 10733 | - | appendStringInfoString(buf, " INDENT"); | - |
| 10734 | - | else | - |
| 10735 | - | appendStringInfoString(buf, " NO INDENT"); | - |
| 10736 | - | } | - |
| 10737 | - | - | |
| 10738 | - | if (xexpr->op == IS_DOCUMENT) | - |
| 10739 | - | appendStringInfoString(buf, " IS DOCUMENT"); | - |
| 10740 | - | else | - |
| 10741 | - | appendStringInfoChar(buf, ')'); | - |
| 10742 | - | } | - |
| 10743 | - | break; | - |
| 10744 | - | - | |
| 10745 | - | case T_NullTest: | - |
| 10746 | - | { | - |
| 10747 | - | NullTest *ntest = (NullTest *) node; | - |
| 10748 | - | - | |
| 10749 | - | if (!PRETTY_PAREN(context)) | - |
| 10750 | - | appendStringInfoChar(buf, '('); | - |
| 10751 | - | get_rule_expr_paren((Node *) ntest->arg, context, true, node); | - |
| 10752 | - | - | |
| 10753 | - | /* | - |
| 10754 | - | * For scalar inputs, we prefer to print as IS [NOT] NULL, | - |
| 10755 | - | * which is shorter and traditional. If it's a rowtype input | - |
| 10756 | - | * but we're applying a scalar test, must print IS [NOT] | - |
| 10757 | - | * DISTINCT FROM NULL to be semantically correct. | - |
| 10758 | - | */ | - |
| 10759 | - | if (ntest->argisrow || | - |
| 10760 | - | !type_is_rowtype(exprType((Node *) ntest->arg))) | - |
| 10761 | - | { | - |
| 10762 | - | switch (ntest->nulltesttype) | - |
| 10763 | - | { | - |
| 10764 | - | case IS_NULL: | - |
| 10765 | - | appendStringInfoString(buf, " IS NULL"); | - |
| 10766 | - | break; | - |
| 10767 | - | case IS_NOT_NULL: | - |
| 10768 | - | appendStringInfoString(buf, " IS NOT NULL"); | - |
| 10769 | - | break; | - |
| 10770 | - | default: | - |
| 10771 | - | elog(ERROR, "unrecognized nulltesttype: %d", | - |
| 10772 | - | (int) ntest->nulltesttype); | - |
| 10773 | - | } | - |
| 10774 | - | } | - |
| 10775 | - | else | - |
| 10776 | - | { | - |
| 10777 | - | switch (ntest->nulltesttype) | - |
| 10778 | - | { | - |
| 10779 | - | case IS_NULL: | - |
| 10780 | - | appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL"); | - |
| 10781 | - | break; | - |
| 10782 | - | case IS_NOT_NULL: | - |
| 10783 | - | appendStringInfoString(buf, " IS DISTINCT FROM NULL"); | - |
| 10784 | - | break; | - |
| 10785 | - | default: | - |
| 10786 | - | elog(ERROR, "unrecognized nulltesttype: %d", | - |
| 10787 | - | (int) ntest->nulltesttype); | - |
| 10788 | - | } | - |
| 10789 | - | } | - |
| 10790 | - | if (!PRETTY_PAREN(context)) | - |
| 10791 | - | appendStringInfoChar(buf, ')'); | - |
| 10792 | - | } | - |
| 10793 | - | break; | - |
| 10794 | - | - | |
| 10795 | - | case T_BooleanTest: | - |
| 10796 | - | { | - |
| 10797 | - | BooleanTest *btest = (BooleanTest *) node; | - |
| 10798 | - | - | |
| 10799 | - | if (!PRETTY_PAREN(context)) | - |
| 10800 | - | appendStringInfoChar(buf, '('); | - |
| 10801 | - | get_rule_expr_paren((Node *) btest->arg, context, false, node); | - |
| 10802 | - | switch (btest->booltesttype) | - |
| 10803 | - | { | - |
| 10804 | - | case IS_TRUE: | - |
| 10805 | - | appendStringInfoString(buf, " IS TRUE"); | - |
| 10806 | - | break; | - |
| 10807 | - | case IS_NOT_TRUE: | - |
| 10808 | - | appendStringInfoString(buf, " IS NOT TRUE"); | - |
| 10809 | - | break; | - |
| 10810 | - | case IS_FALSE: | - |
| 10811 | - | appendStringInfoString(buf, " IS FALSE"); | - |
| 10812 | - | break; | - |
| 10813 | - | case IS_NOT_FALSE: | - |
| 10814 | - | appendStringInfoString(buf, " IS NOT FALSE"); | - |
| 10815 | - | break; | - |
| 10816 | - | case IS_UNKNOWN: | - |
| 10817 | - | appendStringInfoString(buf, " IS UNKNOWN"); | - |
| 10818 | - | break; | - |
| 10819 | - | case IS_NOT_UNKNOWN: | - |
| 10820 | - | appendStringInfoString(buf, " IS NOT UNKNOWN"); | - |
| 10821 | - | break; | - |
| 10822 | - | default: | - |
| 10823 | - | elog(ERROR, "unrecognized booltesttype: %d", | - |
| 10824 | - | (int) btest->booltesttype); | - |
| 10825 | - | } | - |
| 10826 | - | if (!PRETTY_PAREN(context)) | - |
| 10827 | - | appendStringInfoChar(buf, ')'); | - |
| 10828 | - | } | - |
| 10829 | - | break; | - |
| 10830 | - | - | |
| 10831 | - | case T_CoerceToDomain: | - |
| 10832 | - | { | - |
| 10833 | - | CoerceToDomain *ctest = (CoerceToDomain *) node; | - |
| 10834 | - | Node *arg = (Node *) ctest->arg; | - |
| 10835 | - | - | |
| 10836 | - | if (ctest->coercionformat == COERCE_IMPLICIT_CAST && | - |
| 10837 | - | !showimplicit) | - |
| 10838 | - | { | - |
| 10839 | - | /* don't show the implicit cast */ | - |
| 10840 | - | get_rule_expr(arg, context, false); | - |
| 10841 | - | } | - |
| 10842 | - | else | - |
| 10843 | - | { | - |
| 10844 | - | get_coercion_expr(arg, context, | - |
| 10845 | - | ctest->resulttype, | - |
| 10846 | - | ctest->resulttypmod, | - |
| 10847 | - | node); | - |
| 10848 | - | } | - |
| 10849 | - | } | - |
| 10850 | - | break; | - |
| 10851 | - | - | |
| 10852 | - | case T_CoerceToDomainValue: | - |
| 10853 | - | appendStringInfoString(buf, "VALUE"); | - |
| 10854 | - | break; | - |
| 10855 | - | - | |
| 10856 | - | case T_SetToDefault: | - |
| 10857 | - | appendStringInfoString(buf, "DEFAULT"); | - |
| 10858 | - | break; | - |
| 10859 | - | - | |
| 10860 | - | case T_CurrentOfExpr: | - |
| 10861 | - | { | - |
| 10862 | - | CurrentOfExpr *cexpr = (CurrentOfExpr *) node; | - |
| 10863 | - | - | |
| 10864 | - | if (cexpr->cursor_name) | - |
| 10865 | - | appendStringInfo(buf, "CURRENT OF %s", | - |
| 10866 | - | quote_identifier(cexpr->cursor_name)); | - |
| 10867 | - | else | - |
| 10868 | - | appendStringInfo(buf, "CURRENT OF $%d", | - |
| 10869 | - | cexpr->cursor_param); | - |
| 10870 | - | } | - |
| 10871 | - | break; | - |
| 10872 | - | - | |
| 10873 | - | case T_NextValueExpr: | - |
| 10874 | - | { | - |
| 10875 | - | NextValueExpr *nvexpr = (NextValueExpr *) node; | - |
| 10876 | - | - | |
| 10877 | - | /* | - |
| 10878 | - | * This isn't exactly nextval(), but that seems close enough | - |
| 10879 | - | * for EXPLAIN's purposes. | - |
| 10880 | - | */ | - |
| 10881 | - | appendStringInfoString(buf, "nextval("); | - |
| 10882 | - | simple_quote_literal(buf, | - |
| 10883 | - | generate_relation_name(nvexpr->seqid, | - |
| 10884 | - | NIL)); | - |
| 10885 | - | appendStringInfoChar(buf, ')'); | - |
| 10886 | - | } | - |
| 10887 | - | break; | - |
| 10888 | - | - | |
| 10889 | - | case T_InferenceElem: | - |
| 10890 | - | { | - |
| 10891 | - | InferenceElem *iexpr = (InferenceElem *) node; | - |
| 10892 | - | bool save_varprefix; | - |
| 10893 | - | bool need_parens; | - |
| 10894 | - | - | |
| 10895 | - | /* | - |
| 10896 | - | * InferenceElem can only refer to target relation, so a | - |
| 10897 | - | * prefix is not useful, and indeed would cause parse errors. | - |
| 10898 | - | */ | - |
| 10899 | - | save_varprefix = context->varprefix; | - |
| 10900 | - | context->varprefix = false; | - |
| 10901 | - | - | |
| 10902 | - | /* | - |
| 10903 | - | * Parenthesize the element unless it's a simple Var or a bare | - |
| 10904 | - | * function call. Follows pg_get_indexdef_worker(). | - |
| 10905 | - | */ | - |
| 10906 | - | need_parens = !IsA(iexpr->expr, Var); | - |
| 10907 | - | if (IsA(iexpr->expr, FuncExpr) && | - |
| 10908 | - | ((FuncExpr *) iexpr->expr)->funcformat == | - |
| 10909 | - | COERCE_EXPLICIT_CALL) | - |
| 10910 | - | need_parens = false; | - |
| 10911 | - | - | |
| 10912 | - | if (need_parens) | - |
| 10913 | - | appendStringInfoChar(buf, '('); | - |
| 10914 | - | get_rule_expr((Node *) iexpr->expr, | - |
| 10915 | - | context, false); | - |
| 10916 | - | if (need_parens) | - |
| 10917 | - | appendStringInfoChar(buf, ')'); | - |
| 10918 | - | - | |
| 10919 | - | context->varprefix = save_varprefix; | - |
| 10920 | - | - | |
| 10921 | - | if (iexpr->infercollid) | - |
| 10922 | - | appendStringInfo(buf, " COLLATE %s", | - |
| 10923 | - | generate_collation_name(iexpr->infercollid)); | - |
| 10924 | - | - | |
| 10925 | - | /* Add the operator class name, if not default */ | - |
| 10926 | - | if (iexpr->inferopclass) | - |
| 10927 | - | { | - |
| 10928 | - | Oid inferopclass = iexpr->inferopclass; | - |
| 10929 | - | Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass); | - |
| 10930 | - | - | |
| 10931 | - | get_opclass_name(inferopclass, inferopcinputtype, buf); | - |
| 10932 | - | } | - |
| 10933 | - | } | - |
| 10934 | - | break; | - |
| 10935 | - | - | |
| 10936 | - | case T_ReturningExpr: | - |
| 10937 | - | { | - |
| 10938 | - | ReturningExpr *retExpr = (ReturningExpr *) node; | - |
| 10939 | - | - | |
| 10940 | - | /* | - |
| 10941 | - | * We cannot see a ReturningExpr in rule deparsing, only while | - |
| 10942 | - | * EXPLAINing a query plan (ReturningExpr nodes are only ever | - |
| 10943 | - | * adding during query rewriting). Just display the expression | - |
| 10944 | - | * returned (an expanded view column). | - |
| 10945 | - | */ | - |
| 10946 | - | get_rule_expr((Node *) retExpr->retexpr, context, showimplicit); | - |
| 10947 | - | } | - |
| 10948 | - | break; | - |
| 10949 | - | - | |
| 10950 | - | case T_PartitionBoundSpec: | - |
| 10951 | - | { | - |
| 10952 | - | PartitionBoundSpec *spec = (PartitionBoundSpec *) node; | - |
| 10953 | - | ListCell *cell; | - |
| 10954 | - | char *sep; | - |
| 10955 | - | - | |
| 10956 | - | if (spec->is_default) | - |
| 10957 | - | { | - |
| 10958 | - | appendStringInfoString(buf, "DEFAULT"); | - |
| 10959 | - | break; | - |
| 10960 | - | } | - |
| 10961 | - | - | |
| 10962 | - | switch (spec->strategy) | - |
| 10963 | - | { | - |
| 10964 | - | case PARTITION_STRATEGY_HASH: | - |
| 10965 | - | Assert(spec->modulus > 0 && spec->remainder >= 0); | - |
| 10966 | - | Assert(spec->modulus > spec->remainder); | - |
| 10967 | - | - | |
| 10968 | - | appendStringInfoString(buf, "FOR VALUES"); | - |
| 10969 | - | appendStringInfo(buf, " WITH (modulus %d, remainder %d)", | - |
| 10970 | - | spec->modulus, spec->remainder); | - |
| 10971 | - | break; | - |
| 10972 | - | - | |
| 10973 | - | case PARTITION_STRATEGY_LIST: | - |
| 10974 | - | Assert(spec->listdatums != NIL); | - |
| 10975 | - | - | |
| 10976 | - | appendStringInfoString(buf, "FOR VALUES IN ("); | - |
| 10977 | - | sep = ""; | - |
| 10978 | - | foreach(cell, spec->listdatums) | - |
| 10979 | - | { | - |
| 10980 | - | Const *val = lfirst_node(Const, cell); | - |
| 10981 | - | - | |
| 10982 | - | appendStringInfoString(buf, sep); | - |
| 10983 | - | get_const_expr(val, context, -1); | - |
| 10984 | - | sep = ", "; | - |
| 10985 | - | } | - |
| 10986 | - | - | |
| 10987 | - | appendStringInfoChar(buf, ')'); | - |
| 10988 | - | break; | - |
| 10989 | - | - | |
| 10990 | - | case PARTITION_STRATEGY_RANGE: | - |
| 10991 | - | Assert(spec->lowerdatums != NIL && | - |
| 10992 | - | spec->upperdatums != NIL && | - |
| 10993 | - | list_length(spec->lowerdatums) == | - |
| 10994 | - | list_length(spec->upperdatums)); | - |
| 10995 | - | - | |
| 10996 | - | appendStringInfo(buf, "FOR VALUES FROM %s TO %s", | - |
| 10997 | - | get_range_partbound_string(spec->lowerdatums), | - |
| 10998 | - | get_range_partbound_string(spec->upperdatums)); | - |
| 10999 | - | break; | - |
| 11000 | - | - | |
| 11001 | - | default: | - |
| 11002 | - | elog(ERROR, "unrecognized partition strategy: %d", | - |
| 11003 | - | (int) spec->strategy); | - |
| 11004 | - | break; | - |
| 11005 | - | } | - |
| 11006 | - | } | - |
| 11007 | - | break; | - |
| 11008 | - | - | |
| 11009 | - | case T_JsonValueExpr: | - |
| 11010 | - | { | - |
| 11011 | - | JsonValueExpr *jve = (JsonValueExpr *) node; | - |
| 11012 | - | - | |
| 11013 | - | get_rule_expr((Node *) jve->raw_expr, context, false); | - |
| 11014 | - | get_json_format(jve->format, context->buf); | - |
| 11015 | - | } | - |
| 11016 | - | break; | - |
| 11017 | - | - | |
| 11018 | - | case T_JsonConstructorExpr: | - |
| 11019 | - | get_json_constructor((JsonConstructorExpr *) node, context, false); | - |
| 11020 | - | break; | - |
| 11021 | - | - | |
| 11022 | - | case T_JsonIsPredicate: | - |
| 11023 | - | { | - |
| 11024 | - | JsonIsPredicate *pred = (JsonIsPredicate *) node; | - |
| 11025 | - | - | |
| 11026 | - | if (!PRETTY_PAREN(context)) | - |
| 11027 | - | appendStringInfoChar(context->buf, '('); | - |
| 11028 | - | - | |
| 11029 | - | get_rule_expr_paren(pred->expr, context, true, node); | - |
| 11030 | - | - | |
| 11031 | - | appendStringInfoString(context->buf, " IS JSON"); | - |
| 11032 | - | - | |
| 11033 | - | /* TODO: handle FORMAT clause */ | - |
| 11034 | - | - | |
| 11035 | - | switch (pred->item_type) | - |
| 11036 | - | { | - |
| 11037 | - | case JS_TYPE_SCALAR: | - |
| 11038 | - | appendStringInfoString(context->buf, " SCALAR"); | - |
| 11039 | - | break; | - |
| 11040 | - | case JS_TYPE_ARRAY: | - |
| 11041 | - | appendStringInfoString(context->buf, " ARRAY"); | - |
| 11042 | - | break; | - |
| 11043 | - | case JS_TYPE_OBJECT: | - |
| 11044 | - | appendStringInfoString(context->buf, " OBJECT"); | - |
| 11045 | - | break; | - |
| 11046 | - | default: | - |
| 11047 | - | break; | - |
| 11048 | - | } | - |
| 11049 | - | - | |
| 11050 | - | if (pred->unique_keys) | - |
| 11051 | - | appendStringInfoString(context->buf, " WITH UNIQUE KEYS"); | - |
| 11052 | - | - | |
| 11053 | - | if (!PRETTY_PAREN(context)) | - |
| 11054 | - | appendStringInfoChar(context->buf, ')'); | - |
| 11055 | - | } | - |
| 11056 | - | break; | - |
| 11057 | - | - | |
| 11058 | - | case T_JsonExpr: | - |
| 11059 | - | { | - |
| 11060 | - | JsonExpr *jexpr = (JsonExpr *) node; | - |
| 11061 | - | - | |
| 11062 | - | switch (jexpr->op) | - |
| 11063 | - | { | - |
| 11064 | - | case JSON_EXISTS_OP: | - |
| 11065 | - | appendStringInfoString(buf, "JSON_EXISTS("); | - |
| 11066 | - | break; | - |
| 11067 | - | case JSON_QUERY_OP: | - |
| 11068 | - | appendStringInfoString(buf, "JSON_QUERY("); | - |
| 11069 | - | break; | - |
| 11070 | - | case JSON_VALUE_OP: | - |
| 11071 | - | appendStringInfoString(buf, "JSON_VALUE("); | - |
| 11072 | - | break; | - |
| 11073 | - | default: | - |
| 11074 | - | elog(ERROR, "unrecognized JsonExpr op: %d", | - |
| 11075 | - | (int) jexpr->op); | - |
| 11076 | - | } | - |
| 11077 | - | - | |
| 11078 | - | get_rule_expr(jexpr->formatted_expr, context, showimplicit); | - |
| 11079 | - | - | |
| 11080 | - | appendStringInfoString(buf, ", "); | - |
| 11081 | - | - | |
| 11082 | - | get_json_path_spec(jexpr->path_spec, context, showimplicit); | - |
| 11083 | - | - | |
| 11084 | - | if (jexpr->passing_values) | - |
| 11085 | - | { | - |
| 11086 | - | ListCell *lc1, | - |
| 11087 | - | *lc2; | - |
| 11088 | - | bool needcomma = false; | - |
| 11089 | - | - | |
| 11090 | - | appendStringInfoString(buf, " PASSING "); | - |
| 11091 | - | - | |
| 11092 | - | forboth(lc1, jexpr->passing_names, | - |
| 11093 | - | lc2, jexpr->passing_values) | - |
| 11094 | - | { | - |
| 11095 | - | if (needcomma) | - |
| 11096 | - | appendStringInfoString(buf, ", "); | - |
| 11097 | - | needcomma = true; | - |
| 11098 | - | - | |
| 11099 | - | get_rule_expr((Node *) lfirst(lc2), context, showimplicit); | - |
| 11100 | - | appendStringInfo(buf, " AS %s", | - |
| 11101 | - | quote_identifier(lfirst_node(String, lc1)->sval)); | - |
| 11102 | - | } | - |
| 11103 | - | } | - |
| 11104 | - | - | |
| 11105 | - | if (jexpr->op != JSON_EXISTS_OP || | - |
| 11106 | - | jexpr->returning->typid != BOOLOID) | - |
| 11107 | - | get_json_returning(jexpr->returning, context->buf, | - |
| 11108 | - | jexpr->op == JSON_QUERY_OP); | - |
| 11109 | - | - | |
| 11110 | - | get_json_expr_options(jexpr, context, | - |
| 11111 | - | jexpr->op != JSON_EXISTS_OP ? | - |
| 11112 | - | JSON_BEHAVIOR_NULL : | - |
| 11113 | - | JSON_BEHAVIOR_FALSE); | - |
| 11114 | - | - | |
| 11115 | - | appendStringInfoChar(buf, ')'); | - |
| 11116 | - | } | - |
| 11117 | - | break; | - |
| 11118 | - | - | |
| 11119 | - | case T_List: | - |
| 11120 | - | { | - |
| 11121 | - | char *sep; | - |
| 11122 | - | ListCell *l; | - |
| 11123 | - | - | |
| 11124 | - | sep = ""; | - |
| 11125 | - | foreach(l, (List *) node) | - |
| 11126 | - | { | - |
| 11127 | - | appendStringInfoString(buf, sep); | - |
| 11128 | - | get_rule_expr((Node *) lfirst(l), context, showimplicit); | - |
| 11129 | - | sep = ", "; | - |
| 11130 | - | } | - |
| 11131 | - | } | - |
| 11132 | - | break; | - |
| 11133 | - | - | |
| 11134 | - | case T_TableFunc: | - |
| 11135 | - | get_tablefunc((TableFunc *) node, context, showimplicit); | - |
| 11136 | - | break; | - |
| 11137 | - | - | |
| 11138 | 26 | case T_GraphPropertyRef: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 11139 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 11140 | 26 | GraphPropertyRef *gpr = (GraphPropertyRef *) node; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 11141 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 11142 | 26 | appendStringInfo(buf, "%s.%s", quote_identifier(gpr->elvarname), quote_identifier(get_propgraph_property_name(gpr->propid))); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 11143 | 26 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 11144 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 11145 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 11146 | - | default: | - |
| 11147 | - | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); | - |
| 11148 | - | break; | - |
| 11149 | - | } | - |
| 11150 | - | } | - |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 12898 | - | get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) | - |
| 12899 | - | { | - |
| 12900 | - | StringInfo buf = context->buf; | - |
| 12901 | - | deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces); | - |
| 12902 | - | - | |
| 12903 | - | if (IsA(jtnode, RangeTblRef)) | - |
| 12904 | - | { | - |
| 12905 | - | int varno = ((RangeTblRef *) jtnode)->rtindex; | - |
| 12906 | - | RangeTblEntry *rte = rt_fetch(varno, query->rtable); | - |
| 12907 | - | deparse_columns *colinfo = deparse_columns_fetch(varno, dpns); | - |
| 12908 | - | RangeTblFunction *rtfunc1 = NULL; | - |
| 12909 | - | - | |
| 12910 | - | if (rte->lateral) | - |
| 12911 | - | appendStringInfoString(buf, "LATERAL "); | - |
| 12912 | - | - | |
| 12913 | - | /* Print the FROM item proper */ | - |
| 12914 | - | switch (rte->rtekind) | - |
| 12915 | - | { | - |
| 12916 | - | case RTE_RELATION: | - |
| 12917 | - | /* Normal relation RTE */ | - |
| 12918 | - | appendStringInfo(buf, "%s%s", | - |
| 12919 | - | only_marker(rte), | - |
| 12920 | - | generate_relation_name(rte->relid, | - |
| 12921 | - | context->namespaces)); | - |
| 12922 | - | break; | - |
| 12923 | - | case RTE_SUBQUERY: | - |
| 12924 | - | /* Subquery RTE */ | - |
| 12925 | - | appendStringInfoChar(buf, '('); | - |
| 12926 | - | get_query_def(rte->subquery, buf, context->namespaces, NULL, | - |
| 12927 | - | true, | - |
| 12928 | - | context->prettyFlags, context->wrapColumn, | - |
| 12929 | - | context->indentLevel); | - |
| 12930 | - | appendStringInfoChar(buf, ')'); | - |
| 12931 | - | break; | - |
| 12932 | - | case RTE_FUNCTION: | - |
| 12933 | - | /* Function RTE */ | - |
| 12934 | - | rtfunc1 = (RangeTblFunction *) linitial(rte->functions); | - |
| 12935 | - | - | |
| 12936 | - | /* | - |
| 12937 | - | * Omit ROWS FROM() syntax for just one function, unless it | - |
| 12938 | - | * has both a coldeflist and WITH ORDINALITY. If it has both, | - |
| 12939 | - | * we must use ROWS FROM() syntax to avoid ambiguity about | - |
| 12940 | - | * whether the coldeflist includes the ordinality column. | - |
| 12941 | - | */ | - |
| 12942 | - | if (list_length(rte->functions) == 1 && | - |
| 12943 | - | (rtfunc1->funccolnames == NIL || !rte->funcordinality)) | - |
| 12944 | - | { | - |
| 12945 | - | get_rule_expr_funccall(rtfunc1->funcexpr, context, true); | - |
| 12946 | - | /* we'll print the coldeflist below, if it has one */ | - |
| 12947 | - | } | - |
| 12948 | - | else | - |
| 12949 | - | { | - |
| 12950 | - | bool all_unnest; | - |
| 12951 | - | ListCell *lc; | - |
| 12952 | - | - | |
| 12953 | - | /* | - |
| 12954 | - | * If all the function calls in the list are to unnest, | - |
| 12955 | - | * and none need a coldeflist, then collapse the list back | - |
| 12956 | - | * down to UNNEST(args). (If we had more than one | - |
| 12957 | - | * built-in unnest function, this would get more | - |
| 12958 | - | * difficult.) | - |
| 12959 | - | * | - |
| 12960 | - | * XXX This is pretty ugly, since it makes not-terribly- | - |
| 12961 | - | * future-proof assumptions about what the parser would do | - |
| 12962 | - | * with the output; but the alternative is to emit our | - |
| 12963 | - | * nonstandard ROWS FROM() notation for what might have | - |
| 12964 | - | * been a perfectly spec-compliant multi-argument | - |
| 12965 | - | * UNNEST(). | - |
| 12966 | - | */ | - |
| 12967 | - | all_unnest = true; | - |
| 12968 | - | foreach(lc, rte->functions) | - |
| 12969 | - | { | - |
| 12970 | - | RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); | - |
| 12971 | - | - | |
| 12972 | - | if (!IsA(rtfunc->funcexpr, FuncExpr) || | - |
| 12973 | - | ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY || | - |
| 12974 | - | rtfunc->funccolnames != NIL) | - |
| 12975 | - | { | - |
| 12976 | - | all_unnest = false; | - |
| 12977 | - | break; | - |
| 12978 | - | } | - |
| 12979 | - | } | - |
| 12980 | - | - | |
| 12981 | - | if (all_unnest) | - |
| 12982 | - | { | - |
| 12983 | - | List *allargs = NIL; | - |
| 12984 | - | - | |
| 12985 | - | foreach(lc, rte->functions) | - |
| 12986 | - | { | - |
| 12987 | - | RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); | - |
| 12988 | - | List *args = ((FuncExpr *) rtfunc->funcexpr)->args; | - |
| 12989 | - | - | |
| 12990 | - | allargs = list_concat(allargs, args); | - |
| 12991 | - | } | - |
| 12992 | - | - | |
| 12993 | - | appendStringInfoString(buf, "UNNEST("); | - |
| 12994 | - | get_rule_expr((Node *) allargs, context, true); | - |
| 12995 | - | appendStringInfoChar(buf, ')'); | - |
| 12996 | - | } | - |
| 12997 | - | else | - |
| 12998 | - | { | - |
| 12999 | - | int funcno = 0; | - |
| 13000 | - | - | |
| 13001 | - | appendStringInfoString(buf, "ROWS FROM("); | - |
| 13002 | - | foreach(lc, rte->functions) | - |
| 13003 | - | { | - |
| 13004 | - | RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); | - |
| 13005 | - | - | |
| 13006 | - | if (funcno > 0) | - |
| 13007 | - | appendStringInfoString(buf, ", "); | - |
| 13008 | - | get_rule_expr_funccall(rtfunc->funcexpr, context, true); | - |
| 13009 | - | if (rtfunc->funccolnames != NIL) | - |
| 13010 | - | { | - |
| 13011 | - | /* Reconstruct the column definition list */ | - |
| 13012 | - | appendStringInfoString(buf, " AS "); | - |
| 13013 | - | get_from_clause_coldeflist(rtfunc, | - |
| 13014 | - | NULL, | - |
| 13015 | - | context); | - |
| 13016 | - | } | - |
| 13017 | - | funcno++; | - |
| 13018 | - | } | - |
| 13019 | - | appendStringInfoChar(buf, ')'); | - |
| 13020 | - | } | - |
| 13021 | - | /* prevent printing duplicate coldeflist below */ | - |
| 13022 | - | rtfunc1 = NULL; | - |
| 13023 | - | } | - |
| 13024 | - | if (rte->funcordinality) | - |
| 13025 | - | appendStringInfoString(buf, " WITH ORDINALITY"); | - |
| 13026 | - | break; | - |
| 13027 | - | case RTE_TABLEFUNC: | - |
| 13028 | - | get_tablefunc(rte->tablefunc, context, true); | - |
| 13029 | - | break; | - |
| 13030 | 13 | case RTE_GRAPH_TABLE: | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13031 | 13 | appendStringInfoString(buf, "GRAPH_TABLE ("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13032 | 13 | appendStringInfoString(buf, generate_relation_name(rte->relid, context->namespaces)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13033 | 13 | appendStringInfoString(buf, " MATCH "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13034 | 13 | get_graph_pattern_def(rte->graph_pattern, context); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13035 | 13 | appendStringInfoString(buf, " COLUMNS ("); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13036 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13037 | 13 | ListCell *lc; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13038 | 13 | bool first = true; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13039 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 13040 | 26 | foreach(lc, rte->graph_table_columns) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13041 | - | { | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13042 | 13 | TargetEntry *te = lfirst_node(TargetEntry, lc); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13043 | 13 | deparse_context context = {0}; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13044 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 13045 | 13 | if (!first) | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13046 | 0 | appendStringInfoString(buf, ", "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13047 | - | else | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13048 | - | first = false; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13049 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 13050 | 13 | context.buf = buf; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13051 | - | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) | |
| 13052 | 13 | get_rule_expr((Node *) te->expr, &context, false); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13053 | 13 | appendStringInfoString(buf, " AS "); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13054 | 13 | appendStringInfoString(buf, quote_identifier(te->resname)); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13055 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13056 | - | } | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13057 | 13 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13058 | 13 | appendStringInfoString(buf, ")"); | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13059 | 13 | break; | 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 13060 | - | case RTE_VALUES: | - |
| 13061 | - | /* Values list RTE */ | - |
| 13062 | - | appendStringInfoChar(buf, '('); | - |
| 13063 | - | get_values_def(rte->values_lists, context); | - |
| 13064 | - | appendStringInfoChar(buf, ')'); | - |
| 13065 | - | break; | - |
| 13066 | - | case RTE_CTE: | - |
| 13067 | - | appendStringInfoString(buf, quote_identifier(rte->ctename)); | - |
| 13068 | - | break; | - |
| 13069 | - | default: | - |
| 13070 | - | elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); | - |
| 13071 | - | break; | - |
| 13072 | - | } | - |
| 13073 | - | - | |
| 13074 | - | /* Print the relation alias, if needed */ | - |
| 13075 | - | get_rte_alias(rte, varno, false, context); | - |
| 13076 | - | - | |
| 13077 | - | /* Print the column definitions or aliases, if needed */ | - |
| 13078 | - | if (rtfunc1 && rtfunc1->funccolnames != NIL) | - |
| 13079 | - | { | - |
| 13080 | - | /* Reconstruct the columndef list, which is also the aliases */ | - |
| 13081 | - | get_from_clause_coldeflist(rtfunc1, colinfo, context); | - |
| 13082 | - | } | - |
| 13083 | - | else | - |
| 13084 | - | { | - |
| 13085 | - | /* Else print column aliases as needed */ | - |
| 13086 | - | get_column_alias_list(colinfo, context); | - |
| 13087 | - | } | - |
| 13088 | - | - | |
| 13089 | - | /* Tablesample clause must go after any alias */ | - |
| 13090 | - | if (rte->rtekind == RTE_RELATION && rte->tablesample) | - |
| 13091 | - | get_tablesample_def(rte->tablesample, context); | - |
| 13092 | - | } | - |
| 13093 | - | else if (IsA(jtnode, JoinExpr)) | - |
| 13094 | - | { | - |
| 13095 | - | JoinExpr *j = (JoinExpr *) jtnode; | - |
| 13096 | - | deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns); | - |
| 13097 | - | bool need_paren_on_right; | - |
| 13098 | - | - | |
| 13099 | - | need_paren_on_right = PRETTY_PAREN(context) && | - |
| 13100 | - | !IsA(j->rarg, RangeTblRef) && | - |
| 13101 | - | !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL); | - |
| 13102 | - | - | |
| 13103 | - | if (!PRETTY_PAREN(context) || j->alias != NULL) | - |
| 13104 | - | appendStringInfoChar(buf, '('); | - |
| 13105 | - | - | |
| 13106 | - | get_from_clause_item(j->larg, query, context); | - |
| 13107 | - | - | |
| 13108 | - | switch (j->jointype) | - |
| 13109 | - | { | - |
| 13110 | - | case JOIN_INNER: | - |
| 13111 | - | if (j->quals) | - |
| 13112 | - | appendContextKeyword(context, " JOIN ", | - |
| 13113 | - | -PRETTYINDENT_STD, | - |
| 13114 | - | PRETTYINDENT_STD, | - |
| 13115 | - | PRETTYINDENT_JOIN); | - |
| 13116 | - | else | - |
| 13117 | - | appendContextKeyword(context, " CROSS JOIN ", | - |
| 13118 | - | -PRETTYINDENT_STD, | - |
| 13119 | - | PRETTYINDENT_STD, | - |
| 13120 | - | PRETTYINDENT_JOIN); | - |
| 13121 | - | break; | - |
| 13122 | - | case JOIN_LEFT: | - |
| 13123 | - | appendContextKeyword(context, " LEFT JOIN ", | - |
| 13124 | - | -PRETTYINDENT_STD, | - |
| 13125 | - | PRETTYINDENT_STD, | - |
| 13126 | - | PRETTYINDENT_JOIN); | - |
| 13127 | - | break; | - |
| 13128 | - | case JOIN_FULL: | - |
| 13129 | - | appendContextKeyword(context, " FULL JOIN ", | - |
| 13130 | - | -PRETTYINDENT_STD, | - |
| 13131 | - | PRETTYINDENT_STD, | - |
| 13132 | - | PRETTYINDENT_JOIN); | - |
| 13133 | - | break; | - |
| 13134 | - | case JOIN_RIGHT: | - |
| 13135 | - | appendContextKeyword(context, " RIGHT JOIN ", | - |
| 13136 | - | -PRETTYINDENT_STD, | - |
| 13137 | - | PRETTYINDENT_STD, | - |
| 13138 | - | PRETTYINDENT_JOIN); | - |
| 13139 | - | break; | - |
| 13140 | - | default: | - |
| 13141 | - | elog(ERROR, "unrecognized join type: %d", | - |
| 13142 | - | (int) j->jointype); | - |
| 13143 | - | } | - |
| 13144 | - | - | |
| 13145 | - | if (need_paren_on_right) | - |
| 13146 | - | appendStringInfoChar(buf, '('); | - |
| 13147 | - | get_from_clause_item(j->rarg, query, context); | - |
| 13148 | - | if (need_paren_on_right) | - |
| 13149 | - | appendStringInfoChar(buf, ')'); | - |
| 13150 | - | - | |
| 13151 | - | if (j->usingClause) | - |
| 13152 | - | { | - |
| 13153 | - | ListCell *lc; | - |
| 13154 | - | bool first = true; | - |
| 13155 | - | - | |
| 13156 | - | appendStringInfoString(buf, " USING ("); | - |
| 13157 | - | /* Use the assigned names, not what's in usingClause */ | - |
| 13158 | - | foreach(lc, colinfo->usingNames) | - |
| 13159 | - | { | - |
| 13160 | - | char *colname = (char *) lfirst(lc); | - |
| 13161 | - | - | |
| 13162 | - | if (first) | - |
| 13163 | - | first = false; | - |
| 13164 | - | else | - |
| 13165 | - | appendStringInfoString(buf, ", "); | - |
| 13166 | - | appendStringInfoString(buf, quote_identifier(colname)); | - |
| 13167 | - | } | - |
| 13168 | - | appendStringInfoChar(buf, ')'); | - |
| 13169 | - | - | |
| 13170 | - | if (j->join_using_alias) | - |
| 13171 | - | appendStringInfo(buf, " AS %s", | - |
| 13172 | - | quote_identifier(j->join_using_alias->aliasname)); | - |
| 13173 | - | } | - |
| 13174 | - | else if (j->quals) | - |
| 13175 | - | { | - |
| 13176 | - | appendStringInfoString(buf, " ON "); | - |
| 13177 | - | if (!PRETTY_PAREN(context)) | - |
| 13178 | - | appendStringInfoChar(buf, '('); | - |
| 13179 | - | get_rule_expr(j->quals, context, false); | - |
| 13180 | - | if (!PRETTY_PAREN(context)) | - |
| 13181 | - | appendStringInfoChar(buf, ')'); | - |
| 13182 | - | } | - |
| 13183 | - | else if (j->jointype != JOIN_INNER) | - |
| 13184 | - | { | - |
| 13185 | - | /* If we didn't say CROSS JOIN above, we must provide an ON */ | - |
| 13186 | - | appendStringInfoString(buf, " ON TRUE"); | - |
| 13187 | - | } | - |
| 13188 | - | - | |
| 13189 | - | if (!PRETTY_PAREN(context) || j->alias != NULL) | - |
| 13190 | - | appendStringInfoChar(buf, ')'); | - |
| 13191 | - | - | |
| 13192 | - | /* Yes, it's correct to put alias after the right paren ... */ | - |
| 13193 | - | if (j->alias != NULL) | - |
| 13194 | - | { | - |
| 13195 | - | /* | - |
| 13196 | - | * Note that it's correct to emit an alias clause if and only if | - |
| 13197 | - | * there was one originally. Otherwise we'd be converting a named | - |
| 13198 | - | * join to unnamed or vice versa, which creates semantic | - |
| 13199 | - | * subtleties we don't want. However, we might print a different | - |
| 13200 | - | * alias name than was there originally. | - |
| 13201 | - | */ | - |
| 13202 | - | appendStringInfo(buf, " %s", | - |
| 13203 | - | quote_identifier(get_rtable_name(j->rtindex, | - |
| 13204 | - | context))); | - |
| 13205 | - | get_column_alias_list(colinfo, context); | - |
| 13206 | - | } | - |
| 13207 | - | } | - |
| 13208 | - | else | - |
| 13209 | - | elog(ERROR, "unrecognized node type: %d", | - |
| 13210 | - | (int) nodeTag(jtnode)); | - |
| 13211 | - | } | - |