pgsql-v9.2-fix-leaky-view-part-1.v4.patch

application/octet-stream

Filename: pgsql-v9.2-fix-leaky-view-part-1.v4.patch
Type: application/octet-stream
Part: 1
Message: Re: [v9.2] Fix leaky-view problem, part 1
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 1188,1193 **** _copyFuncExpr(FuncExpr *from)
--- 1188,1194 ----
  	COPY_SCALAR_FIELD(inputcollid);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1224,1229 **** _copyOpExpr(OpExpr *from)
--- 1225,1231 ----
  	COPY_SCALAR_FIELD(inputcollid);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1244,1249 **** _copyDistinctExpr(DistinctExpr *from)
--- 1246,1252 ----
  	COPY_SCALAR_FIELD(inputcollid);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1264,1269 **** _copyNullIfExpr(NullIfExpr *from)
--- 1267,1273 ----
  	COPY_SCALAR_FIELD(inputcollid);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1282,1287 **** _copyScalarArrayOpExpr(ScalarArrayOpExpr *from)
--- 1286,1292 ----
  	COPY_SCALAR_FIELD(inputcollid);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1422,1427 **** _copyCoerceViaIO(CoerceViaIO *from)
--- 1427,1433 ----
  	COPY_SCALAR_FIELD(resultcollid);
  	COPY_SCALAR_FIELD(coerceformat);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1442,1447 **** _copyArrayCoerceExpr(ArrayCoerceExpr *from)
--- 1448,1454 ----
  	COPY_SCALAR_FIELD(isExplicit);
  	COPY_SCALAR_FIELD(coerceformat);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1574,1579 **** _copyRowCompareExpr(RowCompareExpr *from)
--- 1581,1587 ----
  	COPY_NODE_FIELD(inputcollids);
  	COPY_NODE_FIELD(largs);
  	COPY_NODE_FIELD(rargs);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 248,253 **** _equalFuncExpr(FuncExpr *a, FuncExpr *b)
--- 248,254 ----
  	COMPARE_SCALAR_FIELD(inputcollid);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 285,290 **** _equalOpExpr(OpExpr *a, OpExpr *b)
--- 286,292 ----
  	COMPARE_SCALAR_FIELD(inputcollid);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 311,316 **** _equalDistinctExpr(DistinctExpr *a, DistinctExpr *b)
--- 313,319 ----
  	COMPARE_SCALAR_FIELD(inputcollid);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 337,342 **** _equalNullIfExpr(NullIfExpr *a, NullIfExpr *b)
--- 340,346 ----
  	COMPARE_SCALAR_FIELD(inputcollid);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 361,366 **** _equalScalarArrayOpExpr(ScalarArrayOpExpr *a, ScalarArrayOpExpr *b)
--- 365,371 ----
  	COMPARE_SCALAR_FIELD(inputcollid);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 479,484 **** _equalCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b)
--- 484,490 ----
  		return false;
  
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 503,508 **** _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b)
--- 509,515 ----
  		return false;
  
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 613,618 **** _equalRowCompareExpr(RowCompareExpr *a, RowCompareExpr *b)
--- 620,626 ----
  	COMPARE_NODE_FIELD(inputcollids);
  	COMPARE_NODE_FIELD(largs);
  	COMPARE_NODE_FIELD(rargs);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 1004,1009 **** _outFuncExpr(StringInfo str, FuncExpr *node)
--- 1004,1010 ----
  	WRITE_OID_FIELD(inputcollid);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1030,1035 **** _outOpExpr(StringInfo str, OpExpr *node)
--- 1031,1037 ----
  	WRITE_OID_FIELD(inputcollid);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1045,1050 **** _outDistinctExpr(StringInfo str, DistinctExpr *node)
--- 1047,1053 ----
  	WRITE_OID_FIELD(inputcollid);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1060,1065 **** _outNullIfExpr(StringInfo str, NullIfExpr *node)
--- 1063,1069 ----
  	WRITE_OID_FIELD(inputcollid);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1073,1078 **** _outScalarArrayOpExpr(StringInfo str, ScalarArrayOpExpr *node)
--- 1077,1083 ----
  	WRITE_OID_FIELD(inputcollid);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1190,1195 **** _outCoerceViaIO(StringInfo str, CoerceViaIO *node)
--- 1195,1201 ----
  	WRITE_OID_FIELD(resultcollid);
  	WRITE_ENUM_FIELD(coerceformat, CoercionForm);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1205,1210 **** _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node)
--- 1211,1217 ----
  	WRITE_BOOL_FIELD(isExplicit);
  	WRITE_ENUM_FIELD(coerceformat, CoercionForm);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1297,1302 **** _outRowCompareExpr(StringInfo str, RowCompareExpr *node)
--- 1304,1310 ----
  	WRITE_NODE_FIELD(inputcollids);
  	WRITE_NODE_FIELD(largs);
  	WRITE_NODE_FIELD(rargs);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
***************
*** 541,546 **** _readFuncExpr(void)
--- 541,547 ----
  	READ_OID_FIELD(inputcollid);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 588,593 **** _readOpExpr(void)
--- 589,595 ----
  	READ_OID_FIELD(inputcollid);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 619,624 **** _readDistinctExpr(void)
--- 621,627 ----
  	READ_OID_FIELD(inputcollid);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 650,655 **** _readNullIfExpr(void)
--- 653,659 ----
  	READ_OID_FIELD(inputcollid);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 679,684 **** _readScalarArrayOpExpr(void)
--- 683,689 ----
  	READ_OID_FIELD(inputcollid);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 794,799 **** _readCoerceViaIO(void)
--- 799,805 ----
  	READ_OID_FIELD(resultcollid);
  	READ_ENUM_FIELD(coerceformat, CoercionForm);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 814,819 **** _readArrayCoerceExpr(void)
--- 820,826 ----
  	READ_BOOL_FIELD(isExplicit);
  	READ_ENUM_FIELD(coerceformat, CoercionForm);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 946,951 **** _readRowCompareExpr(void)
--- 953,959 ----
  	READ_NODE_FIELD(inputcollids);
  	READ_NODE_FIELD(largs);
  	READ_NODE_FIELD(rargs);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
***************
*** 2593,2598 **** cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
--- 2593,2599 ----
  	context.root = root;
  	context.total.startup = 0;
  	context.total.per_tuple = 0;
+ 	context.total.depth = 0;
  
  	/* We don't charge any cost for the implicit ANDing at top level ... */
  
***************
*** 2618,2623 **** cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
--- 2619,2625 ----
  	context.root = root;
  	context.total.startup = 0;
  	context.total.per_tuple = 0;
+ 	context.total.depth = 0;
  
  	cost_qual_eval_walker(qual, &context);
  
***************
*** 2647,2652 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2649,2655 ----
  			locContext.root = context->root;
  			locContext.total.startup = 0;
  			locContext.total.per_tuple = 0;
+ 			locContext.total.depth = 0;
  
  			/*
  			 * For an OR clause, recurse into the marked-up tree so that we
***************
*** 2671,2676 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2674,2681 ----
  		}
  		context->total.startup += rinfo->eval_cost.startup;
  		context->total.per_tuple += rinfo->eval_cost.per_tuple;
+ 		if (rinfo->eval_cost.depth > context->total.depth)
+ 			context->total.depth = rinfo->eval_cost.depth;
  		/* do NOT recurse into children */
  		return false;
  	}
***************
*** 2694,2699 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2699,2706 ----
  	{
  		context->total.per_tuple +=
  			get_func_cost(((FuncExpr *) node)->funcid) * cpu_operator_cost;
+ 		if (((FuncExpr *)node)->depth > context->total.depth)
+ 			context->total.depth = ((FuncExpr *)node)->depth;
  	}
  	else if (IsA(node, OpExpr) ||
  			 IsA(node, DistinctExpr) ||
***************
*** 2703,2708 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2710,2717 ----
  		set_opfuncid((OpExpr *) node);
  		context->total.per_tuple +=
  			get_func_cost(((OpExpr *) node)->opfuncid) * cpu_operator_cost;
+ 		if (((OpExpr *)node)->depth > context->total.depth)
+ 			context->total.depth = ((OpExpr *)node)->depth;
  	}
  	else if (IsA(node, ScalarArrayOpExpr))
  	{
***************
*** 2716,2721 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2725,2732 ----
  		set_sa_opfuncid(saop);
  		context->total.per_tuple += get_func_cost(saop->opfuncid) *
  			cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
+ 		if (saop->depth > context->total.depth)
+ 			context->total.depth = saop->depth;
  	}
  	else if (IsA(node, Aggref) ||
  			 IsA(node, WindowFunc))
***************
*** 2746,2751 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2757,2764 ----
  		getTypeOutputInfo(exprType((Node *) iocoerce->arg),
  						  &iofunc, &typisvarlena);
  		context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost;
+ 		if (iocoerce->depth > context->total.depth)
+ 			context->total.depth = iocoerce->depth;
  	}
  	else if (IsA(node, ArrayCoerceExpr))
  	{
***************
*** 2755,2760 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2768,2775 ----
  		if (OidIsValid(acoerce->elemfuncid))
  			context->total.per_tuple += get_func_cost(acoerce->elemfuncid) *
  				cpu_operator_cost * estimate_array_length(arraynode);
+ 		if (acoerce->depth > context->total.depth)
+ 			context->total.depth = acoerce->depth;
  	}
  	else if (IsA(node, RowCompareExpr))
  	{
***************
*** 2769,2774 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2784,2791 ----
  			context->total.per_tuple += get_func_cost(get_opcode(opid)) *
  				cpu_operator_cost;
  		}
+ 		if (rcexpr->depth > context->total.depth)
+ 			context->total.depth = rcexpr->depth;
  	}
  	else if (IsA(node, CurrentOfExpr))
  	{
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
***************
*** 2704,2709 **** order_qual_clauses(PlannerInfo *root, List *clauses)
--- 2704,2710 ----
  	{
  		Node	   *clause;
  		Cost		cost;
+ 		int			depth;
  	} QualItem;
  	int			nitems = list_length(clauses);
  	QualItem   *items;
***************
*** 2729,2734 **** order_qual_clauses(PlannerInfo *root, List *clauses)
--- 2730,2736 ----
  		cost_qual_eval_node(&qcost, clause, root);
  		items[i].clause = clause;
  		items[i].cost = qcost.per_tuple;
+ 		items[i].depth = qcost.depth;
  		i++;
  	}
  
***************
*** 2745,2751 **** order_qual_clauses(PlannerInfo *root, List *clauses)
  		/* insert newitem into the already-sorted subarray */
  		for (j = i; j > 0; j--)
  		{
! 			if (newitem.cost >= items[j - 1].cost)
  				break;
  			items[j] = items[j - 1];
  		}
--- 2747,2762 ----
  		/* insert newitem into the already-sorted subarray */
  		for (j = i; j > 0; j--)
  		{
! 			/*
! 			 * Higher priority shall be given to the items originated from
! 			 * deeper nest level. If same level, it shall be given to the
! 			 * items with smaller estimated cost.
! 			 * Such kind of consideration is needed to prevent leaky-view
! 			 * problem.
! 			 */
! 			if (newitem.depth < items[j - 1].depth ||
! 				(newitem.depth == items[j - 1].depth &&
! 				 newitem.cost >= items[j - 1].cost))
  				break;
  			items[j] = items[j - 1];
  		}
*** a/src/backend/optimizer/plan/planner.c
--- b/src/backend/optimizer/plan/planner.c
***************
*** 33,38 ****
--- 33,39 ----
  #include "optimizer/subselect.h"
  #include "optimizer/tlist.h"
  #include "optimizer/var.h"
+ #include "nodes/nodeFuncs.h"
  #ifdef OPTIMIZER_DEBUG
  #include "nodes/print.h"
  #endif
***************
*** 104,109 **** static void get_column_info_for_window(PlannerInfo *root, WindowClause *wc,
--- 105,111 ----
  						   int *ordNumCols,
  						   AttrNumber **ordColIdx,
  						   Oid **ordOperators);
+ static void mark_qualifiers_depth(Query *query, int depth);
  
  
  /*****************************************************************************
***************
*** 149,154 **** standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
--- 151,162 ----
  		cursorOptions |= ((DeclareCursorStmt *) parse->utilityStmt)->options;
  
  	/*
+ 	 * Mark qualifiers its original depth to prevent reversal of orders
+ 	 * on evaluation of WHERE clause during relation scanns.
+ 	 */
+ 	mark_qualifiers_depth(parse, 0);
+ 
+ 	/*
  	 * Set up global state for this planner invocation.  This data is needed
  	 * across all levels of sub-Query that might exist in the given command,
  	 * so we keep it in a separate struct that's linked to by each per-Query
***************
*** 2994,2999 **** get_column_info_for_window(PlannerInfo *root, WindowClause *wc, List *tlist,
--- 3002,3127 ----
  	}
  }
  
+ /*
+  * mark_qualifiers_depth
+  *
+  * It marks depth field of the each expression nodes that eventually
+  * invokes functions, to track the original nest-level. On the evaluation
+  * of qualifiers within WHERE or JOIN ... ON clauses during relation scans,
+  * these items shall be reordered according to the nest-level and estimated
+  * cost.
+  * The optimizer may pull-up simple sub-queries or join clause, and
+  * qualifiers to filter out tuples shall be mixed with ones in upper-
+  * level. Thus, we need to track the original nest-level of qualifiers
+  * to prevent reverse of order in evaluation, because some of qualifiers
+  * can have side-effects that allows to leak supplied argument to outside.
+  * It can be abused to break row-level security using a user defined function
+  * with very small estimated cost, so nest level of qualifiers originated
+  * from is used as a criteria, rather than estimated cost, to decide order
+  * to evaluate qualifiers.
+  */
+ static bool
+ mark_qualifiers_depth_walker(Node *node, void *context)
+ {
+ 	int		depth = *((int *)(context));
+ 
+ 	if (node == NULL)
+ 		return false;
+ 	if (IsA(node, FuncExpr))
+ 	{
+ 		FuncExpr   *exp = (FuncExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, OpExpr))
+ 	{
+ 		OpExpr     *exp = (OpExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, DistinctExpr))
+ 	{
+ 		DistinctExpr   *exp = (DistinctExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, ScalarArrayOpExpr))
+ 	{
+ 		ScalarArrayOpExpr  *exp = (ScalarArrayOpExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, CoerceViaIO))
+ 	{
+ 		CoerceViaIO		   *exp = (CoerceViaIO *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, ArrayCoerceExpr))
+ 	{
+ 		ArrayCoerceExpr	   *exp = (ArrayCoerceExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, NullIfExpr))
+ 	{
+ 		NullIfExpr		   *exp = (NullIfExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	else if (IsA(node, RowCompareExpr))
+ 	{
+ 		RowCompareExpr	   *exp = (RowCompareExpr *)node;
+ 
+ 		exp->depth = depth;
+ 
+ 		return false;
+ 	}
+ 	return expression_tree_walker(node, mark_qualifiers_depth_walker, context);
+ }
+ 
+ static void
+ mark_qualifiers_depth(Query *query, int depth)
+ {
+ 	ListCell   *l;
+ 
+ 	foreach (l, query->rtable)
+ 	{
+ 		RangeTblEntry  *rte = lfirst(l);
+ 
+ 		/*
+ 		 * If and when sub-query is defined as a security-barrier,
+ 		 * any qualifiers of WHERE or JOIN ... ON clause must be
+ 		 * launched earlier than ones come from upper nest level,
+ 		 * even if the sub-query is enough simple to be pulled-up
+ 		 * later, because user can reference contents of tuples to
+ 		 * be invisible using functions with side-effect and much
+ 		 * smaller cost estimation.
+ 		 */
+ 		if (rte->rtekind == RTE_SUBQUERY)
+ 		{
+ 			if (rte->security_barrier)
+ 				mark_qualifiers_depth(rte->subquery, depth + 1);
+ 			else
+ 				mark_qualifiers_depth(rte->subquery, depth);
+ 		}
+ 	}
+ 	mark_qualifiers_depth_walker((Node *)query->jointree, &depth);
+ }
  
  /*
   * expression_planner
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
***************
*** 111,116 **** static Expr *simplify_function(Expr *oldexpr, Oid funcid,
--- 111,117 ----
  				  Oid input_collid, List **args,
  				  bool has_named_args,
  				  bool allow_inline,
+ 				  int depth,
  				  eval_const_expressions_context *context);
  static List *reorder_function_arguments(List *args, Oid result_type,
  						   HeapTuple func_tuple,
***************
*** 123,129 **** static void recheck_cast_function_args(List *args, Oid result_type,
  						   HeapTuple func_tuple);
  static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
  				  Oid result_collid, Oid input_collid, List *args,
! 				  HeapTuple func_tuple,
  				  eval_const_expressions_context *context);
  static Expr *inline_function(Oid funcid, Oid result_type, Oid result_collid,
  				Oid input_collid, List *args,
--- 124,130 ----
  						   HeapTuple func_tuple);
  static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
  				  Oid result_collid, Oid input_collid, List *args,
! 				  HeapTuple func_tuple, int depth,
  				  eval_const_expressions_context *context);
  static Expr *inline_function(Oid funcid, Oid result_type, Oid result_collid,
  				Oid input_collid, List *args,
***************
*** 2229,2235 **** eval_const_expressions_mutator(Node *node,
  								   expr->funccollid,
  								   expr->inputcollid,
  								   &args,
! 								   has_named_args, true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
--- 2230,2236 ----
  								   expr->funccollid,
  								   expr->inputcollid,
  								   &args,
! 								   has_named_args, true, expr->depth, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
***************
*** 2248,2253 **** eval_const_expressions_mutator(Node *node,
--- 2249,2255 ----
  		newexpr->inputcollid = expr->inputcollid;
  		newexpr->args = args;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, OpExpr))
***************
*** 2282,2288 **** eval_const_expressions_mutator(Node *node,
  								   expr->opcollid,
  								   expr->inputcollid,
  								   &args,
! 								   false, true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
--- 2284,2290 ----
  								   expr->opcollid,
  								   expr->inputcollid,
  								   &args,
! 								   false, true, expr->depth, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
***************
*** 2313,2318 **** eval_const_expressions_mutator(Node *node,
--- 2315,2321 ----
  		newexpr->inputcollid = expr->inputcollid;
  		newexpr->args = args;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, DistinctExpr))
***************
*** 2380,2386 **** eval_const_expressions_mutator(Node *node,
  									   expr->opcollid,
  									   expr->inputcollid,
  									   &args,
! 									   false, false, context);
  			if (simple)			/* successfully simplified it */
  			{
  				/*
--- 2383,2389 ----
  									   expr->opcollid,
  									   expr->inputcollid,
  									   &args,
! 									   false, false, expr->depth, context);
  			if (simple)			/* successfully simplified it */
  			{
  				/*
***************
*** 2410,2415 **** eval_const_expressions_mutator(Node *node,
--- 2413,2419 ----
  		newexpr->inputcollid = expr->inputcollid;
  		newexpr->args = args;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, BoolExpr))
***************
*** 2570,2576 **** eval_const_expressions_mutator(Node *node,
  								   InvalidOid,
  								   InvalidOid,
  								   &args,
! 								   false, true, context);
  		if (simple)				/* successfully simplified output fn */
  		{
  			/*
--- 2574,2580 ----
  								   InvalidOid,
  								   InvalidOid,
  								   &args,
! 								   false, true, expr->depth, context);
  		if (simple)				/* successfully simplified output fn */
  		{
  			/*
***************
*** 2591,2597 **** eval_const_expressions_mutator(Node *node,
  									   expr->resultcollid,
  									   InvalidOid,
  									   &args,
! 									   false, true, context);
  			if (simple)			/* successfully simplified input fn */
  				return (Node *) simple;
  		}
--- 2595,2601 ----
  									   expr->resultcollid,
  									   InvalidOid,
  									   &args,
! 									   false, true, expr->depth, context);
  			if (simple)			/* successfully simplified input fn */
  				return (Node *) simple;
  		}
***************
*** 2607,2612 **** eval_const_expressions_mutator(Node *node,
--- 2611,2617 ----
  		newexpr->resultcollid = expr->resultcollid;
  		newexpr->coerceformat = expr->coerceformat;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, ArrayCoerceExpr))
***************
*** 2631,2636 **** eval_const_expressions_mutator(Node *node,
--- 2636,2642 ----
  		newexpr->isExplicit = expr->isExplicit;
  		newexpr->coerceformat = expr->coerceformat;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  
  		/*
  		 * If constant argument and it's a binary-coercible or immutable
***************
*** 3447,3452 **** simplify_function(Expr *oldexpr, Oid funcid,
--- 3453,3459 ----
  				  Oid input_collid, List **args,
  				  bool has_named_args,
  				  bool allow_inline,
+ 				  int depth,
  				  eval_const_expressions_context *context)
  {
  	HeapTuple	func_tuple;
***************
*** 3477,3483 **** simplify_function(Expr *oldexpr, Oid funcid,
  
  	newexpr = evaluate_function(funcid, result_type, result_typmod,
  								result_collid, input_collid, *args,
! 								func_tuple, context);
  
  	/*
  	 * Some functions calls can be simplified at plan time based on properties
--- 3484,3490 ----
  
  	newexpr = evaluate_function(funcid, result_type, result_typmod,
  								result_collid, input_collid, *args,
! 								func_tuple, depth, context);
  
  	/*
  	 * Some functions calls can be simplified at plan time based on properties
***************
*** 3764,3770 **** recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
  static Expr *
  evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
  				  Oid result_collid, Oid input_collid, List *args,
! 				  HeapTuple func_tuple,
  				  eval_const_expressions_context *context)
  {
  	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
--- 3771,3777 ----
  static Expr *
  evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
  				  Oid result_collid, Oid input_collid, List *args,
! 				  HeapTuple func_tuple, int depth,
  				  eval_const_expressions_context *context)
  {
  	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
***************
*** 3850,3855 **** evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
--- 3857,3863 ----
  	newexpr->inputcollid = input_collid;
  	newexpr->args = args;
  	newexpr->location = -1;
+ 	newexpr->depth = depth;
  
  	return evaluate_expr((Expr *) newexpr, result_type, result_typmod,
  						 result_collid);
*** a/src/include/nodes/primnodes.h
--- b/src/include/nodes/primnodes.h
***************
*** 335,340 **** typedef struct FuncExpr
--- 335,341 ----
  	Oid			inputcollid;	/* OID of collation that function should use */
  	List	   *args;			/* arguments to the function */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			depth;			/* depth of clause in the original query */
  } FuncExpr;
  
  /*
***************
*** 380,385 **** typedef struct OpExpr
--- 381,387 ----
  	Oid			inputcollid;	/* OID of collation that operator should use */
  	List	   *args;			/* arguments to the operator (1 or 2) */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			depth;			/* depth of clause in the original query */
  } OpExpr;
  
  /*
***************
*** 421,426 **** typedef struct ScalarArrayOpExpr
--- 423,429 ----
  	Oid			inputcollid;	/* OID of collation that operator should use */
  	List	   *args;			/* the scalar and array operands */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			depth;			/* depth of clause in the original query */
  } ScalarArrayOpExpr;
  
  /*
***************
*** 685,690 **** typedef struct CoerceViaIO
--- 688,694 ----
  	Oid			resultcollid;	/* OID of collation, or InvalidOid if none */
  	CoercionForm coerceformat;	/* how to display this node */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			depth;			/* depth of clause in the original query */
  } CoerceViaIO;
  
  /* ----------------
***************
*** 710,715 **** typedef struct ArrayCoerceExpr
--- 714,720 ----
  	bool		isExplicit;		/* conversion semantics flag to pass to func */
  	CoercionForm coerceformat;	/* how to display this node */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			depth;			/* depth of clause in the original query */
  } ArrayCoerceExpr;
  
  /* ----------------
***************
*** 901,906 **** typedef struct RowCompareExpr
--- 906,912 ----
  	List	   *inputcollids;	/* OID list of collations for comparisons */
  	List	   *largs;			/* the left-hand input arguments */
  	List	   *rargs;			/* the right-hand input arguments */
+ 	int			depth;			/* depth of clause in the original query */
  } RowCompareExpr;
  
  /*
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 44,49 **** typedef struct QualCost
--- 44,50 ----
  {
  	Cost		startup;		/* one-time cost */
  	Cost		per_tuple;		/* per-evaluation cost */
+ 	int			depth;			/* depth of qual in the original query */
  } QualCost;
  
  /*
*** a/src/test/regress/expected/select_views.out
--- b/src/test/regress/expected/select_views.out
***************
*** 467,472 **** SELECT name, #thepath FROM iexit ORDER BY 1, 2;
--- 467,486 ----
   I- 580                             |       21
   I- 580                             |       22
   I- 580                             |       22
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        5
+  I- 580/I-680                  Ramp |        6
+  I- 580/I-680                  Ramp |        6
+  I- 580/I-680                  Ramp |        6
   I- 580                        Ramp |        2
   I- 580                        Ramp |        2
   I- 580                        Ramp |        2
***************
*** 717,736 **** SELECT name, #thepath FROM iexit ORDER BY 1, 2;
   I- 580                        Ramp |        8
   I- 580                        Ramp |        8
   I- 580                        Ramp |        8
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        5
-  I- 580/I-680                  Ramp |        6
-  I- 580/I-680                  Ramp |        6
-  I- 580/I-680                  Ramp |        6
   I- 680                             |        2
   I- 680                             |        2
   I- 680                             |        2
--- 731,736 ----
***************
*** 1247,1249 **** SELECT * FROM toyemp WHERE name = 'sharon';
--- 1247,1312 ----
   sharon |  25 | (15,12)  |     12000
  (1 row)
  
+ --
+ -- Test for leaky-view
+ --
+ CREATE USER alice;
+ CREATE FUNCTION f_leak(text, text)
+ 	   RETURNS bool LANGUAGE 'plpgsql'
+ 	   COST 0.00000001
+ 	   AS 'begin raise notice ''% => %'', $1, $2; return true; end';
+ CREATE TABLE credit_cards (
+     name   text,
+     number text,
+     expired    text
+ );
+ INSERT INTO credit_cards VALUES ('alice', '1111-2222-3333-4444', 'Aug-2012'),
+                                 ('bob',   '5555-6666-7777-8888', 'Nov-2016'),
+                                 ('eve',   '9801-2345-6789-0123', 'Jan-2018');
+ CREATE VIEW your_credit_normal AS
+     SELECT * FROM credit_cards WHERE name = getpgusername();
+ CREATE VIEW your_credit_secure WITH (security_barrier) AS
+     SELECT * FROM credit_cards WHERE name = getpgusername();
+ GRANT SELECT ON your_credit_normal TO public;
+ GRANT SELECT ON your_credit_secure TO public;
+ -- run leaky view
+ SET SESSION AUTHORIZATION alice;
+ SELECT * FROM your_credit_normal WHERE f_leak(number,expired);
+ NOTICE:  1111-2222-3333-4444 => Aug-2012
+ NOTICE:  5555-6666-7777-8888 => Nov-2016
+ NOTICE:  9801-2345-6789-0123 => Jan-2018
+  name  |       number        | expired  
+ -------+---------------------+----------
+  alice | 1111-2222-3333-4444 | Aug-2012
+ (1 row)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM your_credit_normal WHERE f_leak(number,expired);
+                                 QUERY PLAN                                
+ --------------------------------------------------------------------------
+  Seq Scan on credit_cards
+    Filter: (f_leak(number, expired) AND (name = (getpgusername())::text))
+ (2 rows)
+ 
+ SELECT * FROM your_credit_secure WHERE f_leak(number,expired);
+ NOTICE:  1111-2222-3333-4444 => Aug-2012
+  name  |       number        | expired  
+ -------+---------------------+----------
+  alice | 1111-2222-3333-4444 | Aug-2012
+ (1 row)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM your_credit_secure WHERE f_leak(number,expired);
+                                 QUERY PLAN                                
+ --------------------------------------------------------------------------
+  Seq Scan on credit_cards
+    Filter: ((name = (getpgusername())::text) AND f_leak(number, expired))
+ (2 rows)
+ 
+ \c -
+ -- cleanups
+ DROP ROLE IF EXISTS alice;
+ DROP FUNCTION IF EXISTS f_leak(text);
+ NOTICE:  function f_leak(text) does not exist, skipping
+ DROP TABLE IF EXISTS credit_cards CASCADE;
+ NOTICE:  drop cascades to 2 other objects
+ DETAIL:  drop cascades to view your_credit_normal
+ drop cascades to view your_credit_secure
*** a/src/test/regress/sql/select_views.sql
--- b/src/test/regress/sql/select_views.sql
***************
*** 8,10 **** SELECT * FROM street;
--- 8,49 ----
  SELECT name, #thepath FROM iexit ORDER BY 1, 2;
  
  SELECT * FROM toyemp WHERE name = 'sharon';
+ 
+ --
+ -- Test for leaky-view
+ --
+ 
+ CREATE USER alice;
+ CREATE FUNCTION f_leak(text, text)
+ 	   RETURNS bool LANGUAGE 'plpgsql'
+ 	   COST 0.00000001
+ 	   AS 'begin raise notice ''% => %'', $1, $2; return true; end';
+ CREATE TABLE credit_cards (
+     name   text,
+     number text,
+     expired    text
+ );
+ INSERT INTO credit_cards VALUES ('alice', '1111-2222-3333-4444', 'Aug-2012'),
+                                 ('bob',   '5555-6666-7777-8888', 'Nov-2016'),
+                                 ('eve',   '9801-2345-6789-0123', 'Jan-2018');
+ CREATE VIEW your_credit_normal AS
+     SELECT * FROM credit_cards WHERE name = getpgusername();
+ CREATE VIEW your_credit_secure WITH (security_barrier) AS
+     SELECT * FROM credit_cards WHERE name = getpgusername();
+ 
+ GRANT SELECT ON your_credit_normal TO public;
+ GRANT SELECT ON your_credit_secure TO public;
+ -- run leaky view
+ SET SESSION AUTHORIZATION alice;
+ 
+ SELECT * FROM your_credit_normal WHERE f_leak(number,expired);
+ EXPLAIN (COSTS OFF) SELECT * FROM your_credit_normal WHERE f_leak(number,expired);
+ 
+ SELECT * FROM your_credit_secure WHERE f_leak(number,expired);
+ EXPLAIN (COSTS OFF) SELECT * FROM your_credit_secure WHERE f_leak(number,expired);
+ 
+ \c -
+ -- cleanups
+ DROP ROLE IF EXISTS alice;
+ DROP FUNCTION IF EXISTS f_leak(text);
+ DROP TABLE IF EXISTS credit_cards CASCADE;