28
28
#include "parser/parse_relation.h"
29
29
#include "parser/parse_target.h"
30
30
#include "parser/parse_type.h"
31
+ #include "parser/parsetree.h"
31
32
#include "utils/builtins.h"
32
33
#include "utils/fmgroids.h"
33
34
#include "utils/lsyscache.h"
37
38
static Oid FuncNameAsType (List * funcname );
38
39
static Node * ParseComplexProjection (ParseState * pstate , char * funcname ,
39
40
Node * first_arg , int location );
41
+ static bool check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup );
40
42
41
43
42
44
/*
@@ -1627,9 +1629,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
1627
1629
void
1628
1630
check_pg_get_expr_args (ParseState * pstate , Oid fnoid , List * args )
1629
1631
{
1630
- bool allowed = false;
1631
1632
Node * arg ;
1632
- int netlevelsup ;
1633
1633
1634
1634
/* if not being called for pg_get_expr, do nothing */
1635
1635
if (fnoid != F_PG_GET_EXPR && fnoid != F_PG_GET_EXPR_EXT )
@@ -1641,66 +1641,98 @@ check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args)
1641
1641
1642
1642
/*
1643
1643
* The first argument must be a Var referencing one of the allowed
1644
- * system-catalog columns. It could be a join alias Var, though.
1644
+ * system-catalog columns. It could be a join alias Var or subquery
1645
+ * reference Var, though, so we need a recursive subroutine to chase
1646
+ * through those possibilities.
1645
1647
*/
1646
1648
Assert (list_length (args ) > 1 );
1647
1649
arg = (Node * ) linitial (args );
1648
- netlevelsup = 0 ;
1649
1650
1650
- restart :
1651
- if (IsA (arg , Var ))
1651
+ if (!check_pg_get_expr_arg (pstate , arg , 0 ))
1652
+ ereport (ERROR ,
1653
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1654
+ errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1655
+ }
1656
+
1657
+ static bool
1658
+ check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup )
1659
+ {
1660
+ if (arg && IsA (arg , Var ))
1652
1661
{
1653
1662
Var * var = (Var * ) arg ;
1654
1663
RangeTblEntry * rte ;
1664
+ AttrNumber attnum ;
1655
1665
1656
1666
netlevelsup += var -> varlevelsup ;
1657
1667
rte = GetRTEByRangeTablePosn (pstate , var -> varno , netlevelsup );
1668
+ attnum = var -> varattno ;
1658
1669
1659
1670
if (rte -> rtekind == RTE_JOIN )
1660
1671
{
1661
- /* Expand join alias reference */
1662
- if (var -> varattno > 0 &&
1663
- var -> varattno <= list_length (rte -> joinaliasvars ))
1672
+ /* Recursively examine join alias variable */
1673
+ if (attnum > 0 &&
1674
+ attnum <= list_length (rte -> joinaliasvars ))
1664
1675
{
1665
- arg = (Node * ) list_nth (rte -> joinaliasvars , var -> varattno - 1 );
1666
- goto restart ;
1676
+ arg = (Node * ) list_nth (rte -> joinaliasvars , attnum - 1 );
1677
+ return check_pg_get_expr_arg ( pstate , arg , netlevelsup ) ;
1667
1678
}
1668
1679
}
1680
+ else if (rte -> rtekind == RTE_SUBQUERY )
1681
+ {
1682
+ /* Subselect-in-FROM: examine sub-select's output expr */
1683
+ TargetEntry * ste = get_tle_by_resno (rte -> subquery -> targetList ,
1684
+ attnum );
1685
+ ParseState mypstate ;
1686
+
1687
+ if (ste == NULL || ste -> resjunk )
1688
+ elog (ERROR , "subquery %s does not have attribute %d" ,
1689
+ rte -> eref -> aliasname , attnum );
1690
+ arg = (Node * ) ste -> expr ;
1691
+
1692
+ /*
1693
+ * Recurse into the sub-select to see what its expr refers to.
1694
+ * We have to build an additional level of ParseState to keep in
1695
+ * step with varlevelsup in the subselect.
1696
+ */
1697
+ MemSet (& mypstate , 0 , sizeof (mypstate ));
1698
+ mypstate .parentParseState = pstate ;
1699
+ mypstate .p_rtable = rte -> subquery -> rtable ;
1700
+ /* don't bother filling the rest of the fake pstate */
1701
+
1702
+ return check_pg_get_expr_arg (& mypstate , arg , 0 );
1703
+ }
1669
1704
else if (rte -> rtekind == RTE_RELATION )
1670
1705
{
1671
1706
switch (rte -> relid )
1672
1707
{
1673
1708
case IndexRelationId :
1674
- if (var -> varattno == Anum_pg_index_indexprs ||
1675
- var -> varattno == Anum_pg_index_indpred )
1676
- allowed = true;
1709
+ if (attnum == Anum_pg_index_indexprs ||
1710
+ attnum == Anum_pg_index_indpred )
1711
+ return true;
1677
1712
break ;
1678
1713
1679
1714
case AttrDefaultRelationId :
1680
- if (var -> varattno == Anum_pg_attrdef_adbin )
1681
- allowed = true;
1715
+ if (attnum == Anum_pg_attrdef_adbin )
1716
+ return true;
1682
1717
break ;
1683
1718
1684
1719
case ProcedureRelationId :
1685
- if (var -> varattno == Anum_pg_proc_proargdefaults )
1686
- allowed = true;
1720
+ if (attnum == Anum_pg_proc_proargdefaults )
1721
+ return true;
1687
1722
break ;
1688
1723
1689
1724
case ConstraintRelationId :
1690
- if (var -> varattno == Anum_pg_constraint_conbin )
1691
- allowed = true;
1725
+ if (attnum == Anum_pg_constraint_conbin )
1726
+ return true;
1692
1727
break ;
1693
1728
1694
1729
case TypeRelationId :
1695
- if (var -> varattno == Anum_pg_type_typdefaultbin )
1696
- allowed = true;
1730
+ if (attnum == Anum_pg_type_typdefaultbin )
1731
+ return true;
1697
1732
break ;
1698
1733
}
1699
1734
}
1700
1735
}
1701
1736
1702
- if (!allowed )
1703
- ereport (ERROR ,
1704
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1705
- errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1737
+ return false;
1706
1738
}
0 commit comments