diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 9cc7b8a..82f7bfb 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -762,6 +762,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 	bool		pseudoconstant = false;
 	bool		maybe_equivalence;
 	bool		maybe_outer_join;
+	bool		maybe_leakable_clause = false;
 	Relids		nullable_relids;
 	RestrictInfo *restrictinfo;
 
@@ -780,6 +781,19 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 		elog(ERROR, "JOIN qualification cannot refer to other relations");
 
 	/*
+	 * 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(relids))
+	{
+		maybe_leakable_clause = contain_leakable_functions(clause);
+		if (maybe_leakable_clause)
+			relids = (!ojscope ? bms_copy(qualscope) : bms_copy(ojscope));
+	}
+
+	/*
 	 * If the clause is variable-free, our normal heuristic for pushing it
 	 * down to just the mentioned rels doesn't work, because there are none.
 	 *
@@ -1030,7 +1044,7 @@ 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_leakable_clause && restrictinfo->mergeopfamilies)
 	{
 		if (maybe_equivalence)
 		{
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index c8b2585..74fc64a 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -86,6 +86,7 @@ static bool contain_subplans_walker(Node *node, void *context);
 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);
@@ -1129,6 +1130,120 @@ contain_nonstrict_functions_walker(Node *node, void *context)
 }
 
 
+
+/*****************************************************************************
+ *		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.
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 19a4a45..196dddf 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -1275,6 +1275,25 @@ get_func_namespace(Oid funcid)
 }
 
 /*
+ * 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.
  */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index e979596..2f6d86d 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -67,6 +67,7 @@ extern bool contain_subplans(Node *clause);
 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);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 066ad76..efffbc7 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -77,6 +77,7 @@ extern RegProcedure get_oprrest(Oid opno);
 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);
