30
30
#include "parser/parse_relation.h"
31
31
#include "parser/parse_target.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"
39
40
static Node * ParseComplexProjection (ParseState * pstate , char * funcname ,
40
41
Node * first_arg );
41
42
static void unknown_attribute (ParseState * pstate , Node * relref , char * attname );
43
+ static bool check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup );
42
44
43
45
44
46
/*
@@ -1265,9 +1267,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
1265
1267
void
1266
1268
check_pg_get_expr_args (ParseState * pstate , Oid fnoid , List * args )
1267
1269
{
1268
- bool allowed = false;
1269
1270
Node * arg ;
1270
- int netlevelsup ;
1271
1271
1272
1272
/* if not being called for pg_get_expr, do nothing */
1273
1273
if (fnoid != F_PG_GET_EXPR && fnoid != F_PG_GET_EXPR_EXT )
@@ -1279,61 +1279,93 @@ check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args)
1279
1279
1280
1280
/*
1281
1281
* The first argument must be a Var referencing one of the allowed
1282
- * system-catalog columns. It could be a join alias Var, though.
1282
+ * system-catalog columns. It could be a join alias Var or subquery
1283
+ * reference Var, though, so we need a recursive subroutine to chase
1284
+ * through those possibilities.
1283
1285
*/
1284
1286
Assert (list_length (args ) > 1 );
1285
1287
arg = (Node * ) linitial (args );
1286
- netlevelsup = 0 ;
1287
1288
1288
- restart :
1289
- if (IsA (arg , Var ))
1289
+ if (!check_pg_get_expr_arg (pstate , arg , 0 ))
1290
+ ereport (ERROR ,
1291
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1292
+ errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1293
+ }
1294
+
1295
+ static bool
1296
+ check_pg_get_expr_arg (ParseState * pstate , Node * arg , int netlevelsup )
1297
+ {
1298
+ if (arg && IsA (arg , Var ))
1290
1299
{
1291
1300
Var * var = (Var * ) arg ;
1292
1301
RangeTblEntry * rte ;
1302
+ AttrNumber attnum ;
1293
1303
1294
1304
netlevelsup += var -> varlevelsup ;
1295
1305
rte = GetRTEByRangeTablePosn (pstate , var -> varno , netlevelsup );
1306
+ attnum = var -> varattno ;
1296
1307
1297
1308
if (rte -> rtekind == RTE_JOIN )
1298
1309
{
1299
- /* Expand join alias reference */
1300
- if (var -> varattno > 0 &&
1301
- var -> varattno <= list_length (rte -> joinaliasvars ))
1310
+ /* Recursively examine join alias variable */
1311
+ if (attnum > 0 &&
1312
+ attnum <= list_length (rte -> joinaliasvars ))
1302
1313
{
1303
- arg = (Node * ) list_nth (rte -> joinaliasvars , var -> varattno - 1 );
1304
- goto restart ;
1314
+ arg = (Node * ) list_nth (rte -> joinaliasvars , attnum - 1 );
1315
+ return check_pg_get_expr_arg ( pstate , arg , netlevelsup ) ;
1305
1316
}
1306
1317
}
1318
+ else if (rte -> rtekind == RTE_SUBQUERY )
1319
+ {
1320
+ /* Subselect-in-FROM: examine sub-select's output expr */
1321
+ TargetEntry * ste = get_tle_by_resno (rte -> subquery -> targetList ,
1322
+ attnum );
1323
+ ParseState mypstate ;
1324
+
1325
+ if (ste == NULL || ste -> resjunk )
1326
+ elog (ERROR , "subquery %s does not have attribute %d" ,
1327
+ rte -> eref -> aliasname , attnum );
1328
+ arg = (Node * ) ste -> expr ;
1329
+
1330
+ /*
1331
+ * Recurse into the sub-select to see what its expr refers to.
1332
+ * We have to build an additional level of ParseState to keep in
1333
+ * step with varlevelsup in the subselect.
1334
+ */
1335
+ MemSet (& mypstate , 0 , sizeof (mypstate ));
1336
+ mypstate .parentParseState = pstate ;
1337
+ mypstate .p_rtable = rte -> subquery -> rtable ;
1338
+ /* don't bother filling the rest of the fake pstate */
1339
+
1340
+ return check_pg_get_expr_arg (& mypstate , arg , 0 );
1341
+ }
1307
1342
else if (rte -> rtekind == RTE_RELATION )
1308
1343
{
1309
1344
switch (rte -> relid )
1310
1345
{
1311
1346
case IndexRelationId :
1312
- if (var -> varattno == Anum_pg_index_indexprs ||
1313
- var -> varattno == Anum_pg_index_indpred )
1314
- allowed = true;
1347
+ if (attnum == Anum_pg_index_indexprs ||
1348
+ attnum == Anum_pg_index_indpred )
1349
+ return true;
1315
1350
break ;
1316
1351
1317
1352
case AttrDefaultRelationId :
1318
- if (var -> varattno == Anum_pg_attrdef_adbin )
1319
- allowed = true;
1353
+ if (attnum == Anum_pg_attrdef_adbin )
1354
+ return true;
1320
1355
break ;
1321
1356
1322
1357
case ConstraintRelationId :
1323
- if (var -> varattno == Anum_pg_constraint_conbin )
1324
- allowed = true;
1358
+ if (attnum == Anum_pg_constraint_conbin )
1359
+ return true;
1325
1360
break ;
1326
1361
1327
1362
case TypeRelationId :
1328
- if (var -> varattno == Anum_pg_type_typdefaultbin )
1329
- allowed = true;
1363
+ if (attnum == Anum_pg_type_typdefaultbin )
1364
+ return true;
1330
1365
break ;
1331
1366
}
1332
1367
}
1333
1368
}
1334
1369
1335
- if (!allowed )
1336
- ereport (ERROR ,
1337
- (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1338
- errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1370
+ return false;
1339
1371
}
0 commit comments