30
30
#include "parser/parse_func.h"
31
31
#include "parser/parse_relation.h"
32
32
#include "parser/parse_type.h"
33
+ #include "parser/parsetree.h"
33
34
#include "utils/builtins.h"
34
35
#include "utils/fmgroids.h"
35
36
#include "utils/lsyscache.h"
@@ -44,6 +45,7 @@ static Oid **gen_cross_product(InhPaths *arginh, int nargs);
44
45
static FieldSelect * setup_field_select (Node * input ,char * attname ,Oid relid );
45
46
static void unknown_attribute (const char * schemaname ,const char * relname ,
46
47
const char * attname );
48
+ static bool check_pg_get_expr_arg (ParseState * pstate ,Node * arg ,int netlevelsup );
47
49
48
50
49
51
/*
@@ -1584,9 +1586,7 @@ GetRTEByRangeTablePosn(ParseState *pstate,
1584
1586
void
1585
1587
check_pg_get_expr_args (ParseState * pstate ,Oid fnoid ,List * args )
1586
1588
{
1587
- bool allowed = false;
1588
1589
Node * arg ;
1589
- int netlevelsup ;
1590
1590
1591
1591
/* if not being called for pg_get_expr, do nothing */
1592
1592
if (fnoid != F_PG_GET_EXPR && fnoid != F_PG_GET_EXPR_EXT )
@@ -1598,59 +1598,91 @@ check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args)
1598
1598
1599
1599
/*
1600
1600
* The first argument must be a Var referencing one of the allowed
1601
- * system-catalog columns. It could be a join alias Var, though.
1601
+ * system-catalog columns. It could be a join alias Var or subquery
1602
+ * reference Var, though, so we need a recursive subroutine to chase
1603
+ * through those possibilities.
1602
1604
*/
1603
1605
Assert (args != NIL );
1604
1606
arg = (Node * )lfirst (args );
1605
- netlevelsup = 0 ;
1606
1607
1607
- restart :
1608
- if (IsA (arg ,Var ))
1608
+ if (!check_pg_get_expr_arg (pstate ,arg ,0 ))
1609
+ ereport (ERROR ,
1610
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1611
+ errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1612
+ }
1613
+
1614
+ static bool
1615
+ check_pg_get_expr_arg (ParseState * pstate ,Node * arg ,int netlevelsup )
1616
+ {
1617
+ if (arg && IsA (arg ,Var ))
1609
1618
{
1610
1619
Var * var = (Var * )arg ;
1611
1620
RangeTblEntry * rte ;
1621
+ AttrNumber attnum ;
1612
1622
1613
1623
netlevelsup += var -> varlevelsup ;
1614
1624
rte = GetRTEByRangeTablePosn (pstate ,var -> varno ,netlevelsup );
1625
+ attnum = var -> varattno ;
1615
1626
1616
1627
if (rte -> rtekind == RTE_JOIN )
1617
1628
{
1618
- /*Expand join aliasreference */
1619
- if (var -> varattno > 0 &&
1620
- var -> varattno <=length (rte -> joinaliasvars ))
1629
+ /*Recursively examine join aliasvariable */
1630
+ if (attnum > 0 &&
1631
+ attnum <=length (rte -> joinaliasvars ))
1621
1632
{
1622
- arg = (Node * )nth (var -> varattno - 1 ,rte -> joinaliasvars );
1623
- goto restart ;
1633
+ arg = (Node * )nth (attnum - 1 ,rte -> joinaliasvars );
1634
+ return check_pg_get_expr_arg ( pstate , arg , netlevelsup ) ;
1624
1635
}
1625
1636
}
1637
+ else if (rte -> rtekind == RTE_SUBQUERY )
1638
+ {
1639
+ /* Subselect-in-FROM: examine sub-select's output expr */
1640
+ TargetEntry * ste = get_tle_by_resno (rte -> subquery -> targetList ,
1641
+ attnum );
1642
+ ParseState mypstate ;
1643
+
1644
+ if (ste == NULL || ste -> resdom -> resjunk )
1645
+ elog (ERROR ,"subquery %s does not have attribute %d" ,
1646
+ rte -> eref -> aliasname ,attnum );
1647
+ arg = (Node * )ste -> expr ;
1648
+
1649
+ /*
1650
+ * Recurse into the sub-select to see what its expr refers to.
1651
+ * We have to build an additional level of ParseState to keep in
1652
+ * step with varlevelsup in the subselect.
1653
+ */
1654
+ MemSet (& mypstate ,0 ,sizeof (mypstate ));
1655
+ mypstate .parentParseState = pstate ;
1656
+ mypstate .p_rtable = rte -> subquery -> rtable ;
1657
+ /* don't bother filling the rest of the fake pstate */
1658
+
1659
+ return check_pg_get_expr_arg (& mypstate ,arg ,0 );
1660
+ }
1626
1661
else if (rte -> rtekind == RTE_RELATION )
1627
1662
{
1628
1663
if (rte -> relid == get_system_catalog_relid (IndexRelationName ))
1629
1664
{
1630
- if (var -> varattno == Anum_pg_index_indexprs ||
1631
- var -> varattno == Anum_pg_index_indpred )
1632
- allowed = true;
1665
+ if (attnum == Anum_pg_index_indexprs ||
1666
+ attnum == Anum_pg_index_indpred )
1667
+ return true;
1633
1668
}
1634
1669
else if (rte -> relid == get_system_catalog_relid (AttrDefaultRelationName ))
1635
1670
{
1636
- if (var -> varattno == Anum_pg_attrdef_adbin )
1637
- allowed = true;
1671
+ if (attnum == Anum_pg_attrdef_adbin )
1672
+ return true;
1638
1673
}
1639
1674
else if (rte -> relid == get_system_catalog_relid (ConstraintRelationName ))
1640
1675
{
1641
- if (var -> varattno == Anum_pg_constraint_conbin )
1642
- allowed = true;
1676
+ if (attnum == Anum_pg_constraint_conbin )
1677
+ return true;
1643
1678
}
1644
1679
else if (rte -> relid == get_system_catalog_relid (TypeRelationName ))
1645
1680
{
1646
- if (var -> varattno == Anum_pg_type_typdefaultbin )
1647
- allowed = true;
1681
+ if (attnum == Anum_pg_type_typdefaultbin )
1682
+ return true;
1648
1683
}
1649
1684
}
1650
1685
}
1651
1686
1652
- if (!allowed )
1653
- ereport (ERROR ,
1654
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1655
- errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1687
+ return false;
1656
1688
}