*** a/src/backend/access/common/reloptions.c
--- b/src/backend/access/common/reloptions.c
***************
*** 66,71 **** static relopt_bool boolRelOpts[] =
--- 66,79 ----
  		},
  		true
  	},
+ 	{
+ 		{
+ 			"security_view",
+ 			"Prevent maximum optimization to prevent data leaks",
+ 			RELOPT_KIND_VIEW
+ 		},
+ 		false
+ 	},
  	/* list terminator */
  	{{NULL}}
  };
***************
*** 777,782 **** extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
--- 785,791 ----
  		case RELKIND_RELATION:
  		case RELKIND_TOASTVALUE:
  		case RELKIND_UNCATALOGED:
+ 		case RELKIND_VIEW:
  			options = heap_reloptions(classForm->relkind, datum, false);
  			break;
  		case RELKIND_INDEX:
***************
*** 1131,1137 **** default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
  		{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
  		offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)},
  		{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
! 		offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_scale_factor)}
  	};
  
  	options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 1140,1148 ----
  		{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
  		offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)},
  		{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
! 		offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_scale_factor)},
! 		{"security_view", RELOPT_TYPE_BOOL,
! 		offsetof(StdRdOptions, security_view)},
  	};
  
  	options = parseRelOptions(reloptions, validate, kind, &numoptions);
***************
*** 1173,1178 **** heap_reloptions(char relkind, Datum reloptions, bool validate)
--- 1184,1191 ----
  			return (bytea *) rdopts;
  		case RELKIND_RELATION:
  			return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+ 		case RELKIND_VIEW:
+ 			return default_reloptions(reloptions, validate, RELOPT_KIND_VIEW);
  		default:
  			/* sequences, composite types and views are not supported */
  			return NULL;
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 264,270 **** static void ATRewriteTables(List **wqueue, LOCKMODE lockmode);
  static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
  static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
  static void ATSimplePermissions(Relation rel, bool allowView);
! static void ATSimplePermissionsRelationOrIndex(Relation rel);
  static void ATSimpleRecursion(List **wqueue, Relation rel,
  				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
  static void ATOneLevelRecursion(List **wqueue, Relation rel,
--- 264,270 ----
  static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode);
  static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);
  static void ATSimplePermissions(Relation rel, bool allowView);
! static void ATSimplePermissionsRelationOrIndex(Relation rel, bool allowView);
  static void ATSimpleRecursion(List **wqueue, Relation rel,
  				  AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
  static void ATOneLevelRecursion(List **wqueue, Relation rel,
***************
*** 2684,2690 **** ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
  			break;
  		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
  		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
! 			ATSimplePermissionsRelationOrIndex(rel);
  			/* This command never recurses */
  			pass = AT_PASS_MISC;
  			break;
--- 2684,2690 ----
  			break;
  		case AT_SetOptions:		/* ALTER COLUMN SET ( options ) */
  		case AT_ResetOptions:	/* ALTER COLUMN RESET ( options ) */
! 			ATSimplePermissionsRelationOrIndex(rel, false);
  			/* This command never recurses */
  			pass = AT_PASS_MISC;
  			break;
***************
*** 2762,2775 **** ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
  			pass = AT_PASS_DROP;
  			break;
  		case AT_SetTableSpace:	/* SET TABLESPACE */
! 			ATSimplePermissionsRelationOrIndex(rel);
  			/* This command never recurses */
  			ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
  			pass = AT_PASS_MISC;	/* doesn't actually matter */
  			break;
  		case AT_SetRelOptions:	/* SET (...) */
  		case AT_ResetRelOptions:		/* RESET (...) */
! 			ATSimplePermissionsRelationOrIndex(rel);
  			/* This command never recurses */
  			/* No command-specific prep needed */
  			pass = AT_PASS_MISC;
--- 2762,2775 ----
  			pass = AT_PASS_DROP;
  			break;
  		case AT_SetTableSpace:	/* SET TABLESPACE */
! 			ATSimplePermissionsRelationOrIndex(rel, false);
  			/* This command never recurses */
  			ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
  			pass = AT_PASS_MISC;	/* doesn't actually matter */
  			break;
  		case AT_SetRelOptions:	/* SET (...) */
  		case AT_ResetRelOptions:		/* RESET (...) */
! 			ATSimplePermissionsRelationOrIndex(rel, true);
  			/* This command never recurses */
  			/* No command-specific prep needed */
  			pass = AT_PASS_MISC;
***************
*** 3558,3571 **** ATSimplePermissions(Relation rel, bool allowView)
   * - Ensure that it is not a system table
   */
  static void
! ATSimplePermissionsRelationOrIndex(Relation rel)
  {
  	if (rel->rd_rel->relkind != RELKIND_RELATION &&
! 		rel->rd_rel->relkind != RELKIND_INDEX)
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
! 				 errmsg("\"%s\" is not a table or index",
! 						RelationGetRelationName(rel))));
  
  	/* Permissions checks */
  	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
--- 3558,3573 ----
   * - Ensure that it is not a system table
   */
  static void
! ATSimplePermissionsRelationOrIndex(Relation rel, bool allowView)
  {
  	if (rel->rd_rel->relkind != RELKIND_RELATION &&
! 		rel->rd_rel->relkind != RELKIND_INDEX &&
! 		(!allowView || rel->rd_rel->relkind != RELKIND_VIEW))
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
! 				 errmsg("\"%s\" is not a table%s or index",
! 						RelationGetRelationName(rel),
! 						allowView ? ", view" : "")));
  
  	/* Permissions checks */
  	if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
***************
*** 7009,7014 **** ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode
--- 7011,7017 ----
  	{
  		case RELKIND_RELATION:
  		case RELKIND_TOASTVALUE:
+ 		case RELKIND_VIEW:
  			(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
  			break;
  		case RELKIND_INDEX:
*** a/src/backend/commands/view.c
--- b/src/backend/commands/view.c
***************
*** 97,103 **** isViewOnTempTable_walker(Node *node, void *context)
   *---------------------------------------------------------------------
   */
  static Oid
! DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
  {
  	Oid			viewOid,
  				namespaceId;
--- 97,104 ----
   *---------------------------------------------------------------------
   */
  static Oid
! DefineVirtualRelation(const RangeVar *relation, List *tlist,
! 					  bool replace, bool security)
  {
  	Oid			viewOid,
  				namespaceId;
***************
*** 148,153 **** DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
--- 149,156 ----
  	{
  		Relation	rel;
  		TupleDesc	descriptor;
+ 		List	   *atcmds = NIL;
+ 		AlterTableCmd  *atcmd;
  
  		/*
  		 * Yes.  Get exclusive lock on the existing view ...
***************
*** 185,190 **** DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
--- 188,205 ----
  		descriptor = BuildDescForRelation(attrList);
  		checkViewTupleDesc(descriptor, rel->rd_att);
  
+ 		if (rel->rd_options || security)
+ 		{
+ 			Node   *node;
+ 
+ 			node = (Node *)makeInteger(security);
+ 			node = (Node *)makeDefElem("security_view", node);
+ 			atcmd = makeNode(AlterTableCmd);
+ 			atcmd->subtype = AT_SetRelOptions;
+ 			atcmd->def = (Node *)list_make1(node);
+ 			atcmds = lappend(atcmds, atcmd);
+ 		}
+ 
  		/*
  		 * If new attributes have been added, we must add pg_attribute entries
  		 * for them.  It is convenient (although overkill) to use the ALTER
***************
*** 192,205 **** DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
  		 */
  		if (list_length(attrList) > rel->rd_att->natts)
  		{
- 			List	   *atcmds = NIL;
  			ListCell   *c;
  			int			skip = rel->rd_att->natts;
  
  			foreach(c, attrList)
  			{
- 				AlterTableCmd *atcmd;
- 
  				if (skip > 0)
  				{
  					skip--;
--- 207,217 ----
***************
*** 210,217 **** DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
  				atcmd->def = (Node *) lfirst(c);
  				atcmds = lappend(atcmds, atcmd);
  			}
- 			AlterTableInternal(viewOid, atcmds, true);
  		}
  
  		/*
  		 * Seems okay, so return the OID of the pre-existing view.
--- 222,230 ----
  				atcmd->def = (Node *) lfirst(c);
  				atcmds = lappend(atcmds, atcmd);
  			}
  		}
+ 		if (atcmds != NIL)
+ 			AlterTableInternal(viewOid, atcmds, true);
  
  		/*
  		 * Seems okay, so return the OID of the pre-existing view.
***************
*** 237,242 **** DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
--- 250,260 ----
  		createStmt->tablespacename = NULL;
  		createStmt->if_not_exists = false;
  
+ 		if (security)
+ 			createStmt->options = lappend(createStmt->options,
+ 										  makeDefElem("security_view",
+ 													  (Node *) makeInteger(true)));
+ 
  		/*
  		 * finally create the relation (this will error out if there's an
  		 * existing view, so we don't need more code to complain if "replace"
***************
*** 470,476 **** DefineView(ViewStmt *stmt, const char *queryString)
  	 * aborted.
  	 */
  	viewOid = DefineVirtualRelation(view, viewParse->targetList,
! 									stmt->replace);
  
  	/*
  	 * The relation we have just created is not visible to any other commands
--- 488,494 ----
  	 * aborted.
  	 */
  	viewOid = DefineVirtualRelation(view, viewParse->targetList,
! 									stmt->replace, stmt->security);
  
  	/*
  	 * The relation we have just created is not visible to any other commands
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 1107,1112 **** _copyFuncExpr(FuncExpr *from)
--- 1107,1113 ----
  	COPY_SCALAR_FIELD(funcformat);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1141,1146 **** _copyOpExpr(OpExpr *from)
--- 1142,1148 ----
  	COPY_SCALAR_FIELD(opretset);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1159,1164 **** _copyDistinctExpr(DistinctExpr *from)
--- 1161,1167 ----
  	COPY_SCALAR_FIELD(opretset);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1176,1181 **** _copyScalarArrayOpExpr(ScalarArrayOpExpr *from)
--- 1179,1185 ----
  	COPY_SCALAR_FIELD(useOr);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1312,1317 **** _copyCoerceViaIO(CoerceViaIO *from)
--- 1316,1322 ----
  	COPY_SCALAR_FIELD(resulttype);
  	COPY_SCALAR_FIELD(coerceformat);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1331,1336 **** _copyArrayCoerceExpr(ArrayCoerceExpr *from)
--- 1336,1342 ----
  	COPY_SCALAR_FIELD(isExplicit);
  	COPY_SCALAR_FIELD(coerceformat);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1444,1449 **** _copyRowCompareExpr(RowCompareExpr *from)
--- 1450,1456 ----
  	COPY_NODE_FIELD(opfamilies);
  	COPY_NODE_FIELD(largs);
  	COPY_NODE_FIELD(rargs);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1514,1519 **** _copyNullIfExpr(NullIfExpr *from)
--- 1521,1527 ----
  	COPY_SCALAR_FIELD(opretset);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_SCALAR_FIELD(depth);
  
  	return newnode;
  }
***************
*** 1671,1676 **** _copyFromExpr(FromExpr *from)
--- 1679,1685 ----
  
  	COPY_NODE_FIELD(fromlist);
  	COPY_NODE_FIELD(quals);
+ 	COPY_SCALAR_FIELD(security_view);
  
  	return newnode;
  }
***************
*** 1824,1829 **** _copyRangeTblEntry(RangeTblEntry *from)
--- 1833,1839 ----
  	COPY_SCALAR_FIELD(rtekind);
  	COPY_SCALAR_FIELD(relid);
  	COPY_NODE_FIELD(subquery);
+ 	COPY_SCALAR_FIELD(security_view);
  	COPY_SCALAR_FIELD(jointype);
  	COPY_NODE_FIELD(joinaliasvars);
  	COPY_NODE_FIELD(funcexpr);
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 238,243 **** _equalFuncExpr(FuncExpr *a, FuncExpr *b)
--- 238,244 ----
  
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 273,278 **** _equalOpExpr(OpExpr *a, OpExpr *b)
--- 274,280 ----
  	COMPARE_SCALAR_FIELD(opretset);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 297,302 **** _equalDistinctExpr(DistinctExpr *a, DistinctExpr *b)
--- 299,305 ----
  	COMPARE_SCALAR_FIELD(opretset);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 320,325 **** _equalScalarArrayOpExpr(ScalarArrayOpExpr *a, ScalarArrayOpExpr *b)
--- 323,329 ----
  	COMPARE_SCALAR_FIELD(useOr);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 434,439 **** _equalCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b)
--- 438,444 ----
  		return false;
  
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 457,462 **** _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b)
--- 462,468 ----
  		return false;
  
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 553,558 **** _equalRowCompareExpr(RowCompareExpr *a, RowCompareExpr *b)
--- 559,565 ----
  	COMPARE_NODE_FIELD(opfamilies);
  	COMPARE_NODE_FIELD(largs);
  	COMPARE_NODE_FIELD(rargs);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 614,619 **** _equalNullIfExpr(NullIfExpr *a, NullIfExpr *b)
--- 621,627 ----
  	COMPARE_SCALAR_FIELD(opretset);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(depth);
  
  	return true;
  }
***************
*** 730,735 **** _equalFromExpr(FromExpr *a, FromExpr *b)
--- 738,744 ----
  {
  	COMPARE_NODE_FIELD(fromlist);
  	COMPARE_NODE_FIELD(quals);
+ 	COMPARE_SCALAR_FIELD(security_view);
  
  	return true;
  }
***************
*** 2170,2175 **** _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
--- 2179,2185 ----
  	COMPARE_SCALAR_FIELD(rtekind);
  	COMPARE_SCALAR_FIELD(relid);
  	COMPARE_NODE_FIELD(subquery);
+ 	COMPARE_SCALAR_FIELD(security_view);
  	COMPARE_SCALAR_FIELD(jointype);
  	COMPARE_NODE_FIELD(joinaliasvars);
  	COMPARE_NODE_FIELD(funcexpr);
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 930,935 **** _outFuncExpr(StringInfo str, FuncExpr *node)
--- 930,936 ----
  	WRITE_ENUM_FIELD(funcformat, CoercionForm);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 954,959 **** _outOpExpr(StringInfo str, OpExpr *node)
--- 955,961 ----
  	WRITE_BOOL_FIELD(opretset);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 967,972 **** _outDistinctExpr(StringInfo str, DistinctExpr *node)
--- 969,975 ----
  	WRITE_BOOL_FIELD(opretset);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 979,984 **** _outScalarArrayOpExpr(StringInfo str, ScalarArrayOpExpr *node)
--- 982,988 ----
  	WRITE_BOOL_FIELD(useOr);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1092,1097 **** _outCoerceViaIO(StringInfo str, CoerceViaIO *node)
--- 1096,1102 ----
  	WRITE_OID_FIELD(resulttype);
  	WRITE_ENUM_FIELD(coerceformat, CoercionForm);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1106,1111 **** _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node)
--- 1111,1117 ----
  	WRITE_BOOL_FIELD(isExplicit);
  	WRITE_ENUM_FIELD(coerceformat, CoercionForm);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1184,1189 **** _outRowCompareExpr(StringInfo str, RowCompareExpr *node)
--- 1190,1196 ----
  	WRITE_NODE_FIELD(opfamilies);
  	WRITE_NODE_FIELD(largs);
  	WRITE_NODE_FIELD(rargs);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1234,1239 **** _outNullIfExpr(StringInfo str, NullIfExpr *node)
--- 1241,1247 ----
  	WRITE_BOOL_FIELD(opretset);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
+ 	WRITE_INT_FIELD(depth);
  }
  
  static void
***************
*** 1341,1346 **** _outFromExpr(StringInfo str, FromExpr *node)
--- 1349,1355 ----
  
  	WRITE_NODE_FIELD(fromlist);
  	WRITE_NODE_FIELD(quals);
+ 	WRITE_BOOL_FIELD(security_view);
  }
  
  /*****************************************************************************
***************
*** 2120,2125 **** _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
--- 2129,2135 ----
  			break;
  		case RTE_SUBQUERY:
  			WRITE_NODE_FIELD(subquery);
+ 			WRITE_BOOL_FIELD(security_view);
  			break;
  		case RTE_JOIN:
  			WRITE_ENUM_FIELD(jointype, JoinType);
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
***************
*** 526,531 **** _readFuncExpr(void)
--- 526,532 ----
  	READ_ENUM_FIELD(funcformat, CoercionForm);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 571,576 **** _readOpExpr(void)
--- 572,578 ----
  	READ_BOOL_FIELD(opretset);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 600,605 **** _readDistinctExpr(void)
--- 602,608 ----
  	READ_BOOL_FIELD(opretset);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 628,633 **** _readScalarArrayOpExpr(void)
--- 631,637 ----
  	READ_BOOL_FIELD(useOr);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 740,745 **** _readCoerceViaIO(void)
--- 744,750 ----
  	READ_OID_FIELD(resulttype);
  	READ_ENUM_FIELD(coerceformat, CoercionForm);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 759,764 **** _readArrayCoerceExpr(void)
--- 764,770 ----
  	READ_BOOL_FIELD(isExplicit);
  	READ_ENUM_FIELD(coerceformat, CoercionForm);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 872,877 **** _readRowCompareExpr(void)
--- 878,884 ----
  	READ_NODE_FIELD(opfamilies);
  	READ_NODE_FIELD(largs);
  	READ_NODE_FIELD(rargs);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 953,958 **** _readNullIfExpr(void)
--- 960,966 ----
  	READ_BOOL_FIELD(opretset);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
+ 	READ_INT_FIELD(depth);
  
  	READ_DONE();
  }
***************
*** 1110,1115 **** _readFromExpr(void)
--- 1118,1124 ----
  
  	READ_NODE_FIELD(fromlist);
  	READ_NODE_FIELD(quals);
+ 	READ_BOOL_FIELD(security_view);
  
  	READ_DONE();
  }
***************
*** 1140,1145 **** _readRangeTblEntry(void)
--- 1149,1155 ----
  			break;
  		case RTE_SUBQUERY:
  			READ_NODE_FIELD(subquery);
+ 			READ_BOOL_FIELD(security_view);
  			break;
  		case RTE_JOIN:
  			READ_ENUM_FIELD(jointype, JoinType);
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
***************
*** 2456,2461 **** cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
--- 2456,2462 ----
  	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 ... */
  
***************
*** 2481,2486 **** cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
--- 2482,2488 ----
  	context.root = root;
  	context.total.startup = 0;
  	context.total.per_tuple = 0;
+ 	context.total.depth = 0;
  
  	cost_qual_eval_walker(qual, &context);
  
***************
*** 2510,2515 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2512,2518 ----
  			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
***************
*** 2534,2539 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2537,2544 ----
  		}
  		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;
  	}
***************
*** 2562,2567 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2567,2574 ----
  	{
  		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) ||
***************
*** 2571,2576 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2578,2585 ----
  		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))
  	{
***************
*** 2584,2589 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2593,2600 ----
  		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, CoerceViaIO))
  	{
***************
*** 2600,2605 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2611,2618 ----
  		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))
  	{
***************
*** 2609,2614 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2622,2629 ----
  		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))
  	{
***************
*** 2623,2628 **** cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
--- 2638,2645 ----
  			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
***************
*** 2443,2448 **** order_qual_clauses(PlannerInfo *root, List *clauses)
--- 2443,2449 ----
  	{
  		Node	   *clause;
  		Cost		cost;
+ 		int			depth;
  	} QualItem;
  	int			nitems = list_length(clauses);
  	QualItem   *items;
***************
*** 2468,2473 **** order_qual_clauses(PlannerInfo *root, List *clauses)
--- 2469,2475 ----
  		cost_qual_eval_node(&qcost, clause, root);
  		items[i].clause = clause;
  		items[i].cost = qcost.per_tuple;
+ 		items[i].depth = qcost.depth;
  		i++;
  	}
  
***************
*** 2484,2490 **** 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];
  		}
--- 2486,2494 ----
  		/* insert newitem into the already-sorted subarray */
  		for (j = i; j > 0; j--)
  		{
! 			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/initsplan.c
--- b/src/backend/optimizer/plan/initsplan.c
***************
*** 40,46 **** int			join_collapse_limit;
  
  static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,
  					bool below_outer_join,
! 					Relids *qualscope, Relids *inner_join_rels);
  static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root,
  				   Relids left_rels, Relids right_rels,
  				   Relids inner_join_rels,
--- 40,47 ----
  
  static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,
  					bool below_outer_join,
! 					Relids *qualscope, Relids *inner_join_rels,
! 					bool below_sec_barriers, Relids *sec_barriers);
  static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root,
  				   Relids left_rels, Relids right_rels,
  				   Relids inner_join_rels,
***************
*** 51,57 **** static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
  						JoinType jointype,
  						Relids qualscope,
  						Relids ojscope,
! 						Relids outerjoin_nonnullable);
  static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
  					  Relids *nullable_relids_p, bool is_pushed_down);
  static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
--- 52,59 ----
  						JoinType jointype,
  						Relids qualscope,
  						Relids ojscope,
! 						Relids outerjoin_nonnullable,
! 						Relids sec_barriers);
  static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
  					  Relids *nullable_relids_p, bool is_pushed_down);
  static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
***************
*** 231,243 **** deconstruct_jointree(PlannerInfo *root)
  {
  	Relids		qualscope;
  	Relids		inner_join_rels;
  
  	/* Start recursion at top of jointree */
! 	Assert(root->parse->jointree != NULL &&
! 		   IsA(root->parse->jointree, FromExpr));
  
! 	return deconstruct_recurse(root, (Node *) root->parse->jointree, false,
! 							   &qualscope, &inner_join_rels);
  }
  
  /*
--- 233,247 ----
  {
  	Relids		qualscope;
  	Relids		inner_join_rels;
+ 	Relids		sec_barriers;
+ 	FromExpr   *f = (FromExpr *)root->parse->jointree;
  
  	/* Start recursion at top of jointree */
! 	Assert(root->parse->jointree != NULL && IsA(f, FromExpr));
  
! 	return deconstruct_recurse(root, (Node *) f, false,
! 							   &qualscope, &inner_join_rels,
! 							   f->security_view, &sec_barriers);
  }
  
  /*
***************
*** 261,267 **** deconstruct_jointree(PlannerInfo *root)
   */
  static List *
  deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
! 					Relids *qualscope, Relids *inner_join_rels)
  {
  	List	   *joinlist;
  
--- 265,272 ----
   */
  static List *
  deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
! 					Relids *qualscope, Relids *inner_join_rels,
! 					bool below_sec_barriers, Relids *sec_barriers)
  {
  	List	   *joinlist;
  
***************
*** 280,285 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
--- 285,293 ----
  		/* A single baserel does not create an inner join */
  		*inner_join_rels = NULL;
  		joinlist = list_make1(jtnode);
+ 		/* Is it in security barrier? */
+ 		*sec_barriers = (below_sec_barriers ?
+ 						 bms_make_singleton(varno) : NULL);
  	}
  	else if (IsA(jtnode, FromExpr))
  	{
***************
*** 295,300 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
--- 303,309 ----
  		 */
  		*qualscope = NULL;
  		*inner_join_rels = NULL;
+ 		*sec_barriers = NULL;
  		joinlist = NIL;
  		remaining = list_length(f->fromlist);
  		foreach(l, f->fromlist)
***************
*** 302,313 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
  			Relids		sub_qualscope;
  			List	   *sub_joinlist;
  			int			sub_members;
  
  			sub_joinlist = deconstruct_recurse(root, lfirst(l),
  											   below_outer_join,
  											   &sub_qualscope,
! 											   inner_join_rels);
  			*qualscope = bms_add_members(*qualscope, sub_qualscope);
  			sub_members = list_length(sub_joinlist);
  			remaining--;
  			if (sub_members <= 1 ||
--- 311,327 ----
  			Relids		sub_qualscope;
  			List	   *sub_joinlist;
  			int			sub_members;
+ 			Relids		sub_barriers;
  
  			sub_joinlist = deconstruct_recurse(root, lfirst(l),
  											   below_outer_join,
  											   &sub_qualscope,
! 											   inner_join_rels,
! 											   below_sec_barriers ?
! 											   true : f->security_view,
! 											   &sub_barriers);
  			*qualscope = bms_add_members(*qualscope, sub_qualscope);
+ 			*sec_barriers = bms_add_members(*sec_barriers, sub_barriers);
  			sub_members = list_length(sub_joinlist);
  			remaining--;
  			if (sub_members <= 1 ||
***************
*** 336,342 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
  
  			distribute_qual_to_rels(root, qual,
  									false, below_outer_join, JOIN_INNER,
! 									*qualscope, NULL, NULL);
  		}
  	}
  	else if (IsA(jtnode, JoinExpr))
--- 350,356 ----
  
  			distribute_qual_to_rels(root, qual,
  									false, below_outer_join, JOIN_INNER,
! 									*qualscope, NULL, NULL, *sec_barriers);
  		}
  	}
  	else if (IsA(jtnode, JoinExpr))
***************
*** 346,351 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
--- 360,367 ----
  					rightids,
  					left_inners,
  					right_inners,
+ 					left_barriers,
+ 					right_barriers,
  					nonnullable_rels,
  					ojscope;
  		List	   *leftjoinlist,
***************
*** 370,381 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
  			case JOIN_INNER:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   below_outer_join,
! 												   &leftids, &left_inners);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													below_outer_join,
! 													&rightids, &right_inners);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = *qualscope;
  				/* Inner join adds no restrictions for quals */
  				nonnullable_rels = NULL;
  				break;
--- 386,402 ----
  			case JOIN_INNER:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   below_outer_join,
! 												   &leftids, &left_inners,
! 												   below_sec_barriers,
! 												   &left_barriers);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													below_outer_join,
! 													&rightids, &right_inners,
! 													below_sec_barriers,
! 													&right_barriers);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = *qualscope;
+ 				*sec_barriers = bms_union(left_barriers, right_barriers);
  				/* Inner join adds no restrictions for quals */
  				nonnullable_rels = NULL;
  				break;
***************
*** 383,417 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
  			case JOIN_ANTI:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   below_outer_join,
! 												   &leftids, &left_inners);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													true,
! 													&rightids, &right_inners);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = bms_union(left_inners, right_inners);
  				nonnullable_rels = leftids;
  				break;
  			case JOIN_SEMI:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   below_outer_join,
! 												   &leftids, &left_inners);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													below_outer_join,
! 													&rightids, &right_inners);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = bms_union(left_inners, right_inners);
  				/* Semi join adds no restrictions for quals */
  				nonnullable_rels = NULL;
  				break;
  			case JOIN_FULL:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   true,
! 												   &leftids, &left_inners);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													true,
! 													&rightids, &right_inners);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = bms_union(left_inners, right_inners);
  				/* each side is both outer and inner */
  				nonnullable_rels = *qualscope;
  				break;
--- 404,453 ----
  			case JOIN_ANTI:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   below_outer_join,
! 												   &leftids, &left_inners,
! 												   below_sec_barriers,
! 												   &left_barriers);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													true,
! 													&rightids, &right_inners,
! 													below_sec_barriers,
! 													&right_barriers);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = bms_union(left_inners, right_inners);
+ 				*sec_barriers = bms_union(left_barriers, right_barriers);
  				nonnullable_rels = leftids;
  				break;
  			case JOIN_SEMI:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   below_outer_join,
! 												   &leftids, &left_inners,
! 												   below_sec_barriers,
! 												   &left_barriers);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													below_outer_join,
! 													&rightids, &right_inners,
! 													below_sec_barriers,
! 													&right_barriers);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = bms_union(left_inners, right_inners);
+ 				*sec_barriers = bms_union(left_barriers, right_barriers);
  				/* Semi join adds no restrictions for quals */
  				nonnullable_rels = NULL;
  				break;
  			case JOIN_FULL:
  				leftjoinlist = deconstruct_recurse(root, j->larg,
  												   true,
! 												   &leftids, &left_inners,
! 												   below_sec_barriers,
! 												   &left_barriers);
  				rightjoinlist = deconstruct_recurse(root, j->rarg,
  													true,
! 													&rightids, &right_inners,
! 													below_sec_barriers,
! 													&right_barriers);
  				*qualscope = bms_union(leftids, rightids);
  				*inner_join_rels = bms_union(left_inners, right_inners);
+ 				*sec_barriers = bms_union(left_barriers, right_barriers);
  				/* each side is both outer and inner */
  				nonnullable_rels = *qualscope;
  				break;
***************
*** 460,466 **** deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
  			distribute_qual_to_rels(root, qual,
  									false, below_outer_join, j->jointype,
  									*qualscope,
! 									ojscope, nonnullable_rels);
  		}
  
  		/* Now we can add the SpecialJoinInfo to join_info_list */
--- 496,503 ----
  			distribute_qual_to_rels(root, qual,
  									false, below_outer_join, j->jointype,
  									*qualscope,
! 									ojscope, nonnullable_rels,
! 									*sec_barriers);
  		}
  
  		/* Now we can add the SpecialJoinInfo to join_info_list */
***************
*** 754,760 **** distribute_qual_to_rels(PlannerInfo *root, Node *clause,
  						JoinType jointype,
  						Relids qualscope,
  						Relids ojscope,
! 						Relids outerjoin_nonnullable)
  {
  	Relids		relids;
  	bool		is_pushed_down;
--- 791,798 ----
  						JoinType jointype,
  						Relids qualscope,
  						Relids ojscope,
! 						Relids outerjoin_nonnullable,
! 						Relids sec_barriers)
  {
  	Relids		relids;
  	bool		is_pushed_down;
***************
*** 762,767 **** distribute_qual_to_rels(PlannerInfo *root, Node *clause,
--- 800,806 ----
  	bool		pseudoconstant = false;
  	bool		maybe_equivalence;
  	bool		maybe_outer_join;
+ 	bool		maybe_leakable_clause = false;
  	Relids		nullable_relids;
  	RestrictInfo *restrictinfo;
  
***************
*** 778,783 **** distribute_qual_to_rels(PlannerInfo *root, Node *clause,
--- 817,824 ----
  		elog(ERROR, "JOIN qualification cannot refer to other relations");
  	if (ojscope && !bms_is_subset(relids, ojscope))
  		elog(ERROR, "JOIN qualification cannot refer to other relations");
+ 	if (sec_barriers && !bms_is_subset(sec_barriers, qualscope))
+ 		elog(ERROR, "Bug? incorrect security barriers");
  
  	/*
  	 * If the clause is variable-free, our normal heuristic for pushing it
***************
*** 834,839 **** distribute_qual_to_rels(PlannerInfo *root, Node *clause,
--- 875,894 ----
  		}
  	}
  
+ 	/*
+ 	 * If the clause contains a leakable function, it may be used to
+ 	 * bypass row-level security using views. In this case, we don't
+ 	 * push down the clause not to evaluate the leakable clause prior
+ 	 * to the row-level policy functions.
+ 	 */
+ 	if (!bms_is_empty(sec_barriers) &&
+ 		contain_leakable_functions(clause) &&
+ 		bms_overlap(relids, sec_barriers))
+ 	{
+ 		maybe_leakable_clause = true;
+ 		relids = bms_add_members(relids, sec_barriers);
+ 	}
+ 
  	/*----------
  	 * Check to see if clause application must be delayed by outer-join
  	 * considerations.
***************
*** 1030,1036 **** distribute_qual_to_rels(PlannerInfo *root, Node *clause,
  	 * If none of the above hold, pass it off to
  	 * distribute_restrictinfo_to_rels().
  	 */
! 	if (restrictinfo->mergeopfamilies)
  	{
  		if (maybe_equivalence)
  		{
--- 1085,1091 ----
  	 * If none of the above hold, pass it off to
  	 * distribute_restrictinfo_to_rels().
  	 */
! 	if (!maybe_leakable_clause && restrictinfo->mergeopfamilies)
  	{
  		if (maybe_equivalence)
  		{
***************
*** 1359,1365 **** process_implied_equality(PlannerInfo *root,
  	 */
  	distribute_qual_to_rels(root, (Node *) clause,
  							true, below_outer_join, JOIN_INNER,
! 							qualscope, NULL, NULL);
  }
  
  /*
--- 1414,1420 ----
  	 */
  	distribute_qual_to_rels(root, (Node *) clause,
  							true, below_outer_join, JOIN_INNER,
! 							qualscope, NULL, NULL, NULL);
  }
  
  /*
*** a/src/backend/optimizer/prep/prepjointree.c
--- b/src/backend/optimizer/prep/prepjointree.c
***************
*** 845,850 **** pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
--- 845,856 ----
  	 */
  
  	/*
+ 	 * If the subquery is originated from security view, we mark it here
+ 	 * to prevent over optimization later.
+ 	 */
+ 	((FromExpr *) subquery->jointree)->security_view = rte->security_view;
+ 
+ 	/*
  	 * Return the adjusted subquery jointree to replace the RangeTblRef entry
  	 * in parent's jointree.
  	 */
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
***************
*** 86,91 **** static bool contain_subplans_walker(Node *node, void *context);
--- 86,92 ----
  static bool contain_mutable_functions_walker(Node *node, void *context);
  static bool contain_volatile_functions_walker(Node *node, void *context);
  static bool contain_nonstrict_functions_walker(Node *node, void *context);
+ static bool contain_leakable_functions_walker(Node *node, void *context);
  static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
  static List *find_nonnullable_vars_walker(Node *node, bool top_level);
  static bool is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK);
***************
*** 103,108 **** static Expr *simplify_function(Oid funcid,
--- 104,110 ----
  				  Oid result_type, int32 result_typmod, 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,
***************
*** 115,121 **** 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, List *args,
! 				  HeapTuple func_tuple,
  				  eval_const_expressions_context *context);
  static Expr *inline_function(Oid funcid, Oid result_type, List *args,
  				HeapTuple func_tuple,
--- 117,123 ----
  						   HeapTuple func_tuple);
  static Expr *evaluate_function(Oid funcid,
  				  Oid result_type, int32 result_typmod, List *args,
! 				  HeapTuple func_tuple, int depth,
  				  eval_const_expressions_context *context);
  static Expr *inline_function(Oid funcid, Oid result_type, List *args,
  				HeapTuple func_tuple,
***************
*** 1129,1134 **** contain_nonstrict_functions_walker(Node *node, void *context)
--- 1131,1250 ----
  }
  
  
+ 
+ /*****************************************************************************
+  *		Check clauses for leakable functions
+  *****************************************************************************/
+ 
+ /*
+  * contain_leakable_functions
+  *	  Recursively search for leakable functions within a clause.
+  *
+  * Returns true if any function call with side-effect is found.
+  * ie, some type-input/output handler will raise an error when given
+  *     argument does not have a valid format.
+  *
+  * When people uses views for row-level security purpose, given qualifiers
+  * come from outside of the view should not be pushed down into the views,
+  * if they have side-effect, because contents of tuples to be filtered out
+  * may be leaked via side-effectable functions within the qualifiers.
+  * 
+  * The idea here is that the planner restrain a part of optimization when
+  * the qualifiers contains leakable functions.
+  * This routine checks whether the given clause contains leakable functions,
+  * or not. If we return false, then the clause is clean.
+  */
+ bool
+ contain_leakable_functions(Node *clause)
+ {
+ 	return contain_leakable_functions_walker(clause, NULL);
+ }
+ 
+ static bool
+ contain_leakable_functions_walker(Node *node, void *context)
+ {
+ 	if (node == NULL)
+ 		return false;
+ 
+ 	if (IsA(node, FuncExpr))
+ 	{
+ 		/*
+ 		 * currently, we have no way to distinguish a safe function and
+ 		 * a leakable one, so all the function call shall be considered
+ 		 * as leakable one.
+ 		 */
+ 		return true;
+ 	}
+ 	else if (IsA(node, OpExpr))
+ 	{
+ 		OpExpr	   *expr = (OpExpr *) node;
+ 
+ 		/*
+ 		 * we assume built-in functions to implement operators are not
+ 		 * leakable, so don't need to prevent optimization.
+ 		 */
+ 		set_opfuncid(expr);
+ 		if (get_func_lang(expr->opfuncid) != INTERNALlanguageId)
+ 			return true;
+ 		/* else fall through to check args */
+ 	}
+ 	else if (IsA(node, DistinctExpr))
+ 	{
+ 		DistinctExpr *expr = (DistinctExpr *) node;
+ 
+ 		set_opfuncid((OpExpr *) expr);
+ 		if (get_func_lang(expr->opfuncid) != INTERNALlanguageId)
+ 			return true;
+ 		/* else fall through to check args */
+ 	}
+ 	else if (IsA(node, ScalarArrayOpExpr))
+ 	{
+ 		ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
+ 
+ 		set_sa_opfuncid(expr);
+ 		if (get_func_lang(expr->opfuncid) != INTERNALlanguageId)
+ 			return true;
+ 		/* else fall through to check args */
+ 	}
+ 	else if (IsA(node, CoerceViaIO) ||
+ 			 IsA(node, ArrayCoerceExpr))
+ 	{
+ 		/*
+ 		 * we assume type-in/out handlers are leakable, even if built-in
+ 		 * functions. 
+ 		 * ie, int4in() raises an error message with given argument,
+ 		 *     if it does not have valid format for numeric value.
+ 		 */
+ 		return true;
+ 	}
+ 	else if (IsA(node, NullIfExpr))
+ 	{
+ 		NullIfExpr *expr = (NullIfExpr *) node;
+ 
+ 		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */
+ 		if (get_func_lang(expr->opfuncid) != INTERNALlanguageId)
+ 			return true;
+ 		/* else fall through to check args */
+ 	}
+ 	else if (IsA(node, RowCompareExpr))
+ 	{
+ 		/* RowCompare probably can't have volatile ops, but check anyway */
+ 		RowCompareExpr *rcexpr = (RowCompareExpr *) node;
+ 		ListCell   *opid;
+ 
+ 		foreach(opid, rcexpr->opnos)
+ 		{
+ 			Oid		funcId = get_opcode(lfirst_oid(opid));
+ 
+ 			if (get_func_lang(funcId) != INTERNALlanguageId)
+ 				return true;
+ 		}
+ 		/* else fall through to check args */
+ 	}
+ 	return expression_tree_walker(node, contain_leakable_functions_walker,
+ 								  context);
+ }
+ 
  /*
   * find_nonnullable_rels
   *		Determine which base rels are forced nonnullable by given clause.
***************
*** 2169,2175 **** eval_const_expressions_mutator(Node *node,
  		simple = simplify_function(expr->funcid,
  								   expr->funcresulttype, exprTypmod(node),
  								   &args,
! 								   has_named_args, true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
--- 2285,2291 ----
  		simple = simplify_function(expr->funcid,
  								   expr->funcresulttype, exprTypmod(node),
  								   &args,
! 								   has_named_args, true, expr->depth, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
***************
*** 2186,2191 **** eval_const_expressions_mutator(Node *node,
--- 2302,2308 ----
  		newexpr->funcformat = expr->funcformat;
  		newexpr->args = args;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, OpExpr))
***************
*** 2217,2223 **** eval_const_expressions_mutator(Node *node,
  		simple = simplify_function(expr->opfuncid,
  								   expr->opresulttype, -1,
  								   &args,
! 								   false, true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
--- 2334,2340 ----
  		simple = simplify_function(expr->opfuncid,
  								   expr->opresulttype, -1,
  								   &args,
! 								   false, true, expr->depth, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
  
***************
*** 2246,2251 **** eval_const_expressions_mutator(Node *node,
--- 2363,2369 ----
  		newexpr->opretset = expr->opretset;
  		newexpr->args = args;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, DistinctExpr))
***************
*** 2310,2316 **** eval_const_expressions_mutator(Node *node,
  			simple = simplify_function(expr->opfuncid,
  									   expr->opresulttype, -1,
  									   &args,
! 									   false, false, context);
  			if (simple)			/* successfully simplified it */
  			{
  				/*
--- 2428,2434 ----
  			simple = simplify_function(expr->opfuncid,
  									   expr->opresulttype, -1,
  									   &args,
! 									   false, false, expr->depth, context);
  			if (simple)			/* successfully simplified it */
  			{
  				/*
***************
*** 2338,2343 **** eval_const_expressions_mutator(Node *node,
--- 2456,2462 ----
  		newexpr->opretset = expr->opretset;
  		newexpr->args = args;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, BoolExpr))
***************
*** 2502,2508 **** eval_const_expressions_mutator(Node *node,
  		simple = simplify_function(outfunc,
  								   CSTRINGOID, -1,
  								   &args,
! 								   false, true, context);
  		if (simple)				/* successfully simplified output fn */
  		{
  			/*
--- 2621,2627 ----
  		simple = simplify_function(outfunc,
  								   CSTRINGOID, -1,
  								   &args,
! 								   false, true, expr->depth, context);
  		if (simple)				/* successfully simplified output fn */
  		{
  			/*
***************
*** 2520,2526 **** eval_const_expressions_mutator(Node *node,
  			simple = simplify_function(infunc,
  									   expr->resulttype, -1,
  									   &args,
! 									   false, true, context);
  			if (simple)			/* successfully simplified input fn */
  				return (Node *) simple;
  		}
--- 2639,2645 ----
  			simple = simplify_function(infunc,
  									   expr->resulttype, -1,
  									   &args,
! 									   false, true, expr->depth, context);
  			if (simple)			/* successfully simplified input fn */
  				return (Node *) simple;
  		}
***************
*** 2535,2540 **** eval_const_expressions_mutator(Node *node,
--- 2654,2660 ----
  		newexpr->resulttype = expr->resulttype;
  		newexpr->coerceformat = expr->coerceformat;
  		newexpr->location = expr->location;
+ 		newexpr->depth = expr->depth;
  		return (Node *) newexpr;
  	}
  	if (IsA(node, ArrayCoerceExpr))
***************
*** 2558,2563 **** eval_const_expressions_mutator(Node *node,
--- 2678,2684 ----
  		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
***************
*** 3292,3297 **** simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
--- 3413,3419 ----
  				  List **args,
  				  bool has_named_args,
  				  bool allow_inline,
+ 				  int depth,
  				  eval_const_expressions_context *context)
  {
  	HeapTuple	func_tuple;
***************
*** 3320,3326 **** simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
  		*args = add_function_defaults(*args, result_type, func_tuple, context);
  
  	newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
! 								func_tuple, context);
  
  	if (!newexpr && allow_inline)
  		newexpr = inline_function(funcid, result_type, *args,
--- 3442,3448 ----
  		*args = add_function_defaults(*args, result_type, func_tuple, context);
  
  	newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
! 								func_tuple, depth, context);
  
  	if (!newexpr && allow_inline)
  		newexpr = inline_function(funcid, result_type, *args,
***************
*** 3571,3577 **** recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
   */
  static Expr *
  evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
! 				  HeapTuple func_tuple,
  				  eval_const_expressions_context *context)
  {
  	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
--- 3693,3699 ----
   */
  static Expr *
  evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
! 				  HeapTuple func_tuple, int depth,
  				  eval_const_expressions_context *context)
  {
  	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
***************
*** 3654,3659 **** evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args,
--- 3776,3782 ----
  	newexpr->funcformat = COERCE_DONTCARE;		/* doesn't matter */
  	newexpr->args = args;
  	newexpr->location = -1;
+ 	newexpr->depth = depth;
  
  	return evaluate_expr((Expr *) newexpr, result_type, result_typmod);
  }
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 310,316 **** static TypeName *TableFuncTypeName(List *columns);
  %type <fun_param_mode> arg_class
  %type <typnam>	func_return func_type
  
! %type <boolean>  TriggerForType OptTemp
  %type <oncommit> OnCommitOption
  
  %type <node>	for_locking_item
--- 310,316 ----
  %type <fun_param_mode> arg_class
  %type <typnam>	func_return func_type
  
! %type <boolean>  TriggerForType OptTemp OptSecurity
  %type <oncommit> OnCommitOption
  
  %type <node>	for_locking_item
***************
*** 6355,6389 **** transaction_mode_list_or_empty:
  /*****************************************************************************
   *
   *	QUERY:
!  *		CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')'
   *			AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
   *
   *****************************************************************************/
  
! ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list
  				AS SelectStmt opt_check_option
  				{
  					ViewStmt *n = makeNode(ViewStmt);
! 					n->view = $4;
  					n->view->istemp = $2;
! 					n->aliases = $5;
! 					n->query = $7;
  					n->replace = false;
  					$$ = (Node *) n;
  				}
! 		| CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list
  				AS SelectStmt opt_check_option
  				{
  					ViewStmt *n = makeNode(ViewStmt);
! 					n->view = $6;
  					n->view->istemp = $4;
! 					n->aliases = $7;
! 					n->query = $9;
  					n->replace = true;
  					$$ = (Node *) n;
  				}
  		;
  
  opt_check_option:
  		WITH CHECK OPTION
  				{
--- 6355,6397 ----
  /*****************************************************************************
   *
   *	QUERY:
!  *		CREATE [ OR REPLACE ] [ TEMP ] [ SECURITY ] VIEW
!  *			<viewname> '('target-list ')'
   *			AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
   *
   *****************************************************************************/
  
! ViewStmt: CREATE OptTemp OptSecurity VIEW qualified_name opt_column_list
  				AS SelectStmt opt_check_option
  				{
  					ViewStmt *n = makeNode(ViewStmt);
! 					n->view = $5;
  					n->view->istemp = $2;
! 					n->aliases = $6;
! 					n->query = $8;
  					n->replace = false;
+ 					n->security = $3;
  					$$ = (Node *) n;
  				}
! 		| CREATE OR REPLACE OptTemp OptSecurity
! 				VIEW qualified_name opt_column_list
  				AS SelectStmt opt_check_option
  				{
  					ViewStmt *n = makeNode(ViewStmt);
! 					n->view = $7;
  					n->view->istemp = $4;
! 					n->aliases = $8;
! 					n->query = $10;
  					n->replace = true;
+ 					n->security = $5;
  					$$ = (Node *) n;
  				}
  		;
  
+ OptSecurity:	SECURITY			{ $$ = TRUE; }
+ 		|		/* EMPTY */			{ $$ = FALSE; }
+ 		;
+ 
  opt_check_option:
  		WITH CHECK OPTION
  				{
*** a/src/backend/rewrite/rewriteHandler.c
--- b/src/backend/rewrite/rewriteHandler.c
***************
*** 1132,1137 **** matchLocks(CmdType event,
--- 1132,1251 ----
  	return matching_locks;
  }
  
+ /*
+  * MarkFuncExprDepth
+  *
+  * It marks the depth field of each expression node that may eventually
+  * call functions. On the checks of WHERE clause, every qualifiers are
+  * sorted by cost estimation, then a qualifier with lower-cost shall
+  * be evaluated ealier than expensive one.
+  * However, this logic can cause a problem when simple subqueries are
+  * pull-up to join clauses. If a view is used to row-level security
+  * purpose, its security policy function should be evaluated earlier
+  * than any functions supplied by users, because they may have side-
+  * effects that leaks given arguments somewhere, alhough it is contents
+  * of tuples to be filtered out.
+  * So, we need to ensure a function originated from inner subquery
+  * being evaluated earlier than functions originated from outer
+  * subqueries.
+  */
+ static bool
+ MarkFuncExprDepthWalker(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;
+ 	}
+ 	else if (IsA(node, Query))
+ 	{
+ 		query_tree_walker((Query *)node,
+ 						  MarkFuncExprDepthWalker,
+ 						  (void *)(depth + 1), 0);
+ 		return false;
+ 	}
+ 	return expression_tree_walker(node, MarkFuncExprDepthWalker, context);
+ }
+ 
+ static void
+ MarkFuncExprDepth(List *query_list)
+ {
+ 	ListCell   *l;
+ 
+ 	foreach (l, query_list)
+ 	{
+ 		Node   *node = lfirst(l);
+ 
+ 		Assert(IsA(node, Query));
+ 
+ 		query_tree_walker((Query *)node,
+ 						  MarkFuncExprDepthWalker,
+ 						  (void *) 1, 0);
+ 	}
+ }
  
  /*
   * ApplyRetrieveRule - expand an ON SELECT rule
***************
*** 1188,1193 **** ApplyRetrieveRule(Query *parsetree,
--- 1302,1311 ----
  	rte->subquery = rule_action;
  	rte->inh = false;			/* must not be set for a subquery */
  
+ 	if (relation->rd_options &&
+ 		((StdRdOptions *)relation->rd_options)->security_view)
+ 		rte->security_view = true;
+ 
  	/*
  	 * We move the view's permission check data down to its rangetable. The
  	 * checks will actually be done against the OLD entry therein.
***************
*** 1961,1965 **** QueryRewrite(Query *parsetree)
--- 2079,2088 ----
  	if (!foundOriginalQuery && lastInstead != NULL)
  		lastInstead->canSetTag = true;
  
+ 	/*
+ 	 * Mark the ->depth fields of expression nodes
+ 	 */
+ 	MarkFuncExprDepth(results);
+ 
  	return results;
  }
*** a/src/backend/utils/cache/lsyscache.c
--- b/src/backend/utils/cache/lsyscache.c
***************
*** 1275,1280 **** get_func_namespace(Oid funcid)
--- 1275,1299 ----
  }
  
  /*
+  * get_func_lang
+  *		Given procedure id, return the function's language
+  */
+ Oid
+ get_func_lang(Oid funcid)
+ {
+ 	HeapTuple	tp;
+ 	Oid			result;
+ 
+ 	tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
+ 	if (!HeapTupleIsValid(tp))
+ 		elog(ERROR, "cache lookup failed for function %u", funcid);
+ 
+ 	result = ((Form_pg_proc) GETSTRUCT(tp))->prolang;
+ 	ReleaseSysCache(tp);
+ 	return result;
+ }
+ 
+ /*
   * get_func_rettype
   *		Given procedure id, return the function's result type.
   */
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
***************
*** 385,390 **** RelationParseRelOptions(Relation relation, HeapTuple tuple)
--- 385,391 ----
  		case RELKIND_RELATION:
  		case RELKIND_TOASTVALUE:
  		case RELKIND_INDEX:
+ 		case RELKIND_VIEW:
  			break;
  		default:
  			return;
*** a/src/include/access/reloptions.h
--- b/src/include/access/reloptions.h
***************
*** 42,49 **** typedef enum relopt_kind
  	RELOPT_KIND_GIST = (1 << 5),
  	RELOPT_KIND_ATTRIBUTE = (1 << 6),
  	RELOPT_KIND_TABLESPACE = (1 << 7),
  	/* if you add a new kind, make sure you update "last_default" too */
! 	RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_TABLESPACE,
  	/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
  	RELOPT_KIND_MAX = (1 << 30)
  } relopt_kind;
--- 42,50 ----
  	RELOPT_KIND_GIST = (1 << 5),
  	RELOPT_KIND_ATTRIBUTE = (1 << 6),
  	RELOPT_KIND_TABLESPACE = (1 << 7),
+ 	RELOPT_KIND_VIEW = (1 << 8),
  	/* if you add a new kind, make sure you update "last_default" too */
! 	RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_VIEW,
  	/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
  	RELOPT_KIND_MAX = (1 << 30)
  } relopt_kind;
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 684,689 **** typedef struct RangeTblEntry
--- 684,691 ----
  	 */
  	Query	   *subquery;		/* the sub-query */
  
+ 	bool		security_view;	/* Is the sub-query come from security view? */
+ 
  	/*
  	 * Fields valid for a join RTE (else NULL/zero):
  	 *
***************
*** 2186,2191 **** typedef struct ViewStmt
--- 2188,2194 ----
  	List	   *aliases;		/* target column names */
  	Node	   *query;			/* the SELECT query */
  	bool		replace;		/* replace an existing view? */
+ 	bool		security;		/* the view for row-level security? */
  } ViewStmt;
  
  /* ----------------------
*** a/src/include/nodes/primnodes.h
--- b/src/include/nodes/primnodes.h
***************
*** 325,330 **** typedef struct FuncExpr
--- 325,331 ----
  	CoercionForm funcformat;	/* how to display this function call */
  	List	   *args;			/* arguments to the function */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			depth;			/* depth of clause in the original query */
  } FuncExpr;
  
  /*
***************
*** 368,373 **** typedef struct OpExpr
--- 369,375 ----
  	bool		opretset;		/* true if operator returns set */
  	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;
  
  /*
***************
*** 400,405 **** typedef struct ScalarArrayOpExpr
--- 402,408 ----
  	bool		useOr;			/* true for ANY, false for ALL */
  	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;
  
  /*
***************
*** 659,664 **** typedef struct CoerceViaIO
--- 662,668 ----
  	/* output typmod is not stored, but is presumed -1 */
  	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;
  
  /* ----------------
***************
*** 683,688 **** typedef struct ArrayCoerceExpr
--- 687,693 ----
  	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;
  
  /* ----------------
***************
*** 852,857 **** typedef struct RowCompareExpr
--- 857,863 ----
  	List	   *opfamilies;		/* OID list of containing operator families */
  	List	   *largs;			/* the left-hand input arguments */
  	List	   *rargs;			/* the right-hand input arguments */
+ 	int			depth;			/* depth of clause in the original query */
  } RowCompareExpr;
  
  /*
***************
*** 1208,1213 **** typedef struct FromExpr
--- 1214,1220 ----
  	NodeTag		type;
  	List	   *fromlist;		/* List of join subtrees */
  	Node	   *quals;			/* qualifiers on join, if any */
+ 	bool		security_view;	/* It came from security views */
  } FromExpr;
  
  #endif   /* PRIMNODES_H */
*** 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/include/optimizer/clauses.h
--- b/src/include/optimizer/clauses.h
***************
*** 67,72 **** extern bool contain_subplans(Node *clause);
--- 67,73 ----
  extern bool contain_mutable_functions(Node *clause);
  extern bool contain_volatile_functions(Node *clause);
  extern bool contain_nonstrict_functions(Node *clause);
+ extern bool contain_leakable_functions(Node *clause);
  extern Relids find_nonnullable_rels(Node *clause);
  extern List *find_nonnullable_vars(Node *clause);
  extern List *find_forced_null_vars(Node *clause);
*** a/src/include/utils/lsyscache.h
--- b/src/include/utils/lsyscache.h
***************
*** 77,82 **** extern RegProcedure get_oprrest(Oid opno);
--- 77,83 ----
  extern RegProcedure get_oprjoin(Oid opno);
  extern char *get_func_name(Oid funcid);
  extern Oid	get_func_namespace(Oid funcid);
+ extern Oid	get_func_lang(Oid funcid);
  extern Oid	get_func_rettype(Oid funcid);
  extern int	get_func_nargs(Oid funcid);
  extern Oid	get_func_signature(Oid funcid, Oid **argtypes, int *nargs);
*** a/src/include/utils/rel.h
--- b/src/include/utils/rel.h
***************
*** 242,247 **** typedef struct StdRdOptions
--- 242,248 ----
  	int32		vl_len_;		/* varlena header (do not touch directly!) */
  	int			fillfactor;		/* page fill factor in percent (0..100) */
  	AutoVacOpts autovacuum;		/* autovacuum-related options */
+ 	bool		security_view;	/* prevent full optimization due to RLS */
  } StdRdOptions;
  
  #define HEAP_MIN_FILLFACTOR			10
