3030#include "parser/parse_func.h"
3131#include "parser/parse_relation.h"
3232#include "parser/parse_type.h"
33+ #include "parser/parsetree.h"
3334#include "utils/builtins.h"
3435#include "utils/fmgroids.h"
3536#include "utils/lsyscache.h"
@@ -44,6 +45,7 @@ static Oid **gen_cross_product(InhPaths *arginh, int nargs);
4445static FieldSelect * setup_field_select (Node * input , char * attname , Oid relid );
4546static void unknown_attribute (const char * schemaname , const char * relname ,
4647 const char * attname );
48+ static bool check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup );
4749
4850
4951/*
@@ -1584,9 +1586,7 @@ GetRTEByRangeTablePosn(ParseState *pstate,
15841586void
15851587check_pg_get_expr_args (ParseState * pstate , Oid fnoid , List * args )
15861588{
1587- bool allowed = false;
15881589 Node * arg ;
1589- int netlevelsup ;
15901590
15911591 /* if not being called for pg_get_expr, do nothing */
15921592 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)
15981598
15991599 /*
16001600 * 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.
16021604 */
16031605 Assert (args != NIL );
16041606 arg = (Node * ) lfirst (args );
1605- netlevelsup = 0 ;
16061607
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 ))
16091618 {
16101619 Var * var = (Var * ) arg ;
16111620 RangeTblEntry * rte ;
1621+ AttrNumber attnum ;
16121622
16131623 netlevelsup += var -> varlevelsup ;
16141624 rte = GetRTEByRangeTablePosn (pstate , var -> varno , netlevelsup );
1625+ attnum = var -> varattno ;
16151626
16161627 if (rte -> rtekind == RTE_JOIN )
16171628 {
1618- /* Expand join alias reference */
1619- if (var -> varattno > 0 &&
1620- var -> varattno <= length (rte -> joinaliasvars ))
1629+ /* Recursively examine join alias variable */
1630+ if (attnum > 0 &&
1631+ attnum <= length (rte -> joinaliasvars ))
16211632 {
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 ) ;
16241635 }
16251636 }
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+ }
16261661 else if (rte -> rtekind == RTE_RELATION )
16271662 {
16281663 if (rte -> relid == get_system_catalog_relid (IndexRelationName ))
16291664 {
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;
16331668 }
16341669 else if (rte -> relid == get_system_catalog_relid (AttrDefaultRelationName ))
16351670 {
1636- if (var -> varattno == Anum_pg_attrdef_adbin )
1637- allowed = true;
1671+ if (attnum == Anum_pg_attrdef_adbin )
1672+ return true;
16381673 }
16391674 else if (rte -> relid == get_system_catalog_relid (ConstraintRelationName ))
16401675 {
1641- if (var -> varattno == Anum_pg_constraint_conbin )
1642- allowed = true;
1676+ if (attnum == Anum_pg_constraint_conbin )
1677+ return true;
16431678 }
16441679 else if (rte -> relid == get_system_catalog_relid (TypeRelationName ))
16451680 {
1646- if (var -> varattno == Anum_pg_type_typdefaultbin )
1647- allowed = true;
1681+ if (attnum == Anum_pg_type_typdefaultbin )
1682+ return true;
16481683 }
16491684 }
16501685 }
16511686
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;
16561688}
0 commit comments