2929#include "parser/parse_func.h"
3030#include "parser/parse_relation.h"
3131#include "parser/parse_type.h"
32+ #include "parser/parsetree.h"
3233#include "utils/builtins.h"
3334#include "utils/fmgroids.h"
3435#include "utils/lsyscache.h"
@@ -42,6 +43,7 @@ static Oid **argtype_inherit(int nargs, Oid *argtypes);
4243static int find_inheritors (Oid relid , Oid * * supervec );
4344static Oid * * gen_cross_product (InhPaths * arginh , int nargs );
4445static void unknown_attribute (ParseState * pstate , Node * relref , char * attname );
46+ static bool check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup );
4547
4648
4749/*
@@ -1439,9 +1441,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
14391441void
14401442check_pg_get_expr_args (ParseState * pstate , Oid fnoid , List * args )
14411443{
1442- bool allowed = false;
14431444 Node * arg ;
1444- int netlevelsup ;
14451445
14461446 /* if not being called for pg_get_expr, do nothing */
14471447 if (fnoid != F_PG_GET_EXPR && fnoid != F_PG_GET_EXPR_EXT )
@@ -1453,59 +1453,91 @@ check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args)
14531453
14541454 /*
14551455 * The first argument must be a Var referencing one of the allowed
1456- * system-catalog columns. It could be a join alias Var, though.
1456+ * system-catalog columns. It could be a join alias Var or subquery
1457+ * reference Var, though, so we need a recursive subroutine to chase
1458+ * through those possibilities.
14571459 */
14581460 Assert (list_length (args ) > 1 );
14591461 arg = (Node * ) linitial (args );
1460- netlevelsup = 0 ;
14611462
1462- restart :
1463- if (IsA (arg , Var ))
1463+ if (!check_pg_get_expr_arg (pstate , arg , 0 ))
1464+ ereport (ERROR ,
1465+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1466+ errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1467+ }
1468+
1469+ static bool
1470+ check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup )
1471+ {
1472+ if (arg && IsA (arg , Var ))
14641473 {
14651474 Var * var = (Var * ) arg ;
14661475 RangeTblEntry * rte ;
1476+ AttrNumber attnum ;
14671477
14681478 netlevelsup += var -> varlevelsup ;
14691479 rte = GetRTEByRangeTablePosn (pstate , var -> varno , netlevelsup );
1480+ attnum = var -> varattno ;
14701481
14711482 if (rte -> rtekind == RTE_JOIN )
14721483 {
1473- /* Expand join alias reference */
1474- if (var -> varattno > 0 &&
1475- var -> varattno <= list_length (rte -> joinaliasvars ))
1484+ /* Recursively examine join alias variable */
1485+ if (attnum > 0 &&
1486+ attnum <= list_length (rte -> joinaliasvars ))
14761487 {
1477- arg = (Node * ) list_nth (rte -> joinaliasvars , var -> varattno - 1 );
1478- goto restart ;
1488+ arg = (Node * ) list_nth (rte -> joinaliasvars , attnum - 1 );
1489+ return check_pg_get_expr_arg ( pstate , arg , netlevelsup ) ;
14791490 }
14801491 }
1492+ else if (rte -> rtekind == RTE_SUBQUERY )
1493+ {
1494+ /* Subselect-in-FROM: examine sub-select's output expr */
1495+ TargetEntry * ste = get_tle_by_resno (rte -> subquery -> targetList ,
1496+ attnum );
1497+ ParseState mypstate ;
1498+
1499+ if (ste == NULL || ste -> resdom -> resjunk )
1500+ elog (ERROR , "subquery %s does not have attribute %d" ,
1501+ rte -> eref -> aliasname , attnum );
1502+ arg = (Node * ) ste -> expr ;
1503+
1504+ /*
1505+ * Recurse into the sub-select to see what its expr refers to.
1506+ * We have to build an additional level of ParseState to keep in
1507+ * step with varlevelsup in the subselect.
1508+ */
1509+ MemSet (& mypstate , 0 , sizeof (mypstate ));
1510+ mypstate .parentParseState = pstate ;
1511+ mypstate .p_rtable = rte -> subquery -> rtable ;
1512+ /* don't bother filling the rest of the fake pstate */
1513+
1514+ return check_pg_get_expr_arg (& mypstate , arg , 0 );
1515+ }
14811516 else if (rte -> rtekind == RTE_RELATION )
14821517 {
14831518 if (rte -> relid == get_system_catalog_relid (IndexRelationName ))
14841519 {
1485- if (var -> varattno == Anum_pg_index_indexprs ||
1486- var -> varattno == Anum_pg_index_indpred )
1487- allowed = true;
1520+ if (attnum == Anum_pg_index_indexprs ||
1521+ attnum == Anum_pg_index_indpred )
1522+ return true;
14881523 }
14891524 else if (rte -> relid == get_system_catalog_relid (AttrDefaultRelationName ))
14901525 {
1491- if (var -> varattno == Anum_pg_attrdef_adbin )
1492- allowed = true;
1526+ if (attnum == Anum_pg_attrdef_adbin )
1527+ return true;
14931528 }
14941529 else if (rte -> relid == get_system_catalog_relid (ConstraintRelationName ))
14951530 {
1496- if (var -> varattno == Anum_pg_constraint_conbin )
1497- allowed = true;
1531+ if (attnum == Anum_pg_constraint_conbin )
1532+ return true;
14981533 }
14991534 else if (rte -> relid == get_system_catalog_relid (TypeRelationName ))
15001535 {
1501- if (var -> varattno == Anum_pg_type_typdefaultbin )
1502- allowed = true;
1536+ if (attnum == Anum_pg_type_typdefaultbin )
1537+ return true;
15031538 }
15041539 }
15051540 }
15061541
1507- if (!allowed )
1508- ereport (ERROR ,
1509- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1510- errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1542+ return false;
15111543}
0 commit comments