diff --git a/doc/src/sgml/ref/alter_view.sgml b/doc/src/sgml/ref/alter_view.sgml
index 00f4ecb..d1f3a54 100644
--- a/doc/src/sgml/ref/alter_view.sgml
+++ b/doc/src/sgml/ref/alter_view.sgml
@@ -142,6 +142,16 @@ ALTER VIEW [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RESET
          </para>
         </listitem>
        </varlistentry>
+       <varlistentry>
+        <term><literal>security_definer</literal> (<type>boolean</type>)</term>
+        <listitem>
+         <para>
+          Changes the security-definer property of the view.  The value must
+          be Boolean value, such as <literal>true</literal>
+          or <literal>false</literal>.
+         </para>
+        </listitem>
+       </varlistentry>
       </variablelist>
      </para>
     </listitem>
diff --git a/doc/src/sgml/ref/create_view.sgml b/doc/src/sgml/ref/create_view.sgml
index e37bb00..71c6f79 100644
--- a/doc/src/sgml/ref/create_view.sgml
+++ b/doc/src/sgml/ref/create_view.sgml
@@ -147,6 +147,16 @@ CREATE VIEW <replaceable>name</> AS WITH RECURSIVE <replaceable>name</> (<replac
          </para>
         </listitem>
        </varlistentry>
+       
+       <varlistentry>
+        <term><literal>security_definer</literal> (<type>boolean</type>)</term>
+        <listitem>
+         <para>
+          This should be used if the view is intended to be executed with
+          owner privileges rather than the current user.
+         </para>
+        </listitem>
+       </varlistentry>
       </variablelist>
      </para>
     </listitem>
@@ -276,6 +286,37 @@ CREATE VIEW vista AS SELECT text 'Hello World' AS hello;
     to replace it (this includes being a member of the owning role).
    </para>
 
+  <refsect2 id="SQL-CREATEVIEW-security-definer-views">
+   <title id="SQL-CREATEVIEW-security-definer-views-title">Security definer Views</title>
+
+   <indexterm zone="sql-createview-security-definer-views">
+    <primary>security definer views</primary>
+   </indexterm>
+
+   <para>
+    Security definer views uses the view owner id instead of the current user
+    in the following conditions, otherwise the current user is used to verify
+    the privileges and etc.
+    <itemizedlist>
+     <listitem>
+      <para>
+       The view is used in <command>INSERT</>, <command>UPDATE</>
+       and <command>DELETE</> statements in the same way as on a
+       regular table.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       To apply row-level security policies on the underlying base
+       relations of the view, based on the security definer, the 
+       corresponding policies related to the user are applied.
+      </para>
+     </listitem>
+    </itemizedlist>
+   </para>
+  </refsect2>
+ 
   <refsect2 id="SQL-CREATEVIEW-updatable-views">
    <title id="SQL-CREATEVIEW-updatable-views-title">Updatable Views</title>
 
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 931dceb..430ea71 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -89,6 +89,15 @@ static relopt_bool boolRelOpts[] =
 		},
 		false
 	},
+	{
+		{
+			"security_definer",
+			"specifies that the view is to be executed with the privileges of the user that created it.",
+			RELOPT_KIND_VIEW,
+			AccessExclusiveLock
+		},
+		false
+	},
 	/* list terminator */
 	{{NULL}}
 };
@@ -1320,6 +1329,8 @@ view_reloptions(Datum reloptions, bool validate)
 	static const relopt_parse_elt tab[] = {
 		{"security_barrier", RELOPT_TYPE_BOOL,
 		offsetof(ViewOptions, security_barrier)},
+		{ "security_definer", RELOPT_TYPE_BOOL,
+		offsetof(ViewOptions, security_definer) },
 		{"check_option", RELOPT_TYPE_STRING,
 		offsetof(ViewOptions, check_option_offset)}
 	};
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 315d00c..ea5edaf 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -24,6 +24,7 @@
 #include "catalog/pg_type.h"
 #include "commands/trigger.h"
 #include "foreign/fdwapi.h"
+#include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/analyze.h"
@@ -1616,6 +1617,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
 	int			origResultRelation = parsetree->resultRelation;
 	int			rt_index;
 	ListCell   *lc;
+	bool		security_definer_view = false;
 
 	/*
 	 * don't try to convert this into a foreach loop, because rtable list can
@@ -1777,18 +1779,27 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
 		++rt_index;
 
 		/* Only normal relations can have RLS policies */
-		if (rte->rtekind != RTE_RELATION ||
-			rte->relkind != RELKIND_RELATION)
+		if (rte->rtekind != RTE_RELATION)
 			continue;
-
+		
 		rel = heap_open(rte->relid, NoLock);
 
+		if (rte->relkind == RELKIND_VIEW && RelationIsSecurityDefinerView(rel))
+			security_definer_view = true;
+
+		if (rte->relkind != RELKIND_RELATION)
+		{
+			heap_close(rel, NoLock);
+			continue;
+		}
+
 		/*
 		 * Fetch any new security quals that must be applied to this RTE.
 		 */
 		get_row_security_policies(parsetree, rte, rt_index,
 								  &securityQuals, &withCheckOptions,
-								  &hasRowSecurity, &hasSubLinks);
+								  &hasRowSecurity, &hasSubLinks,
+								  security_definer_view);
 
 		if (securityQuals != NIL || withCheckOptions != NIL)
 		{
@@ -2834,7 +2845,10 @@ rewriteTargetView(Query *parsetree, Relation view)
 	 * the executor still performs appropriate permissions checks for the
 	 * query caller's use of the view.
 	 */
-	new_rte->checkAsUser = view->rd_rel->relowner;
+	if (RelationIsSecurityDefinerView(view))
+		new_rte->checkAsUser = view->rd_rel->relowner;
+	else
+		new_rte->checkAsUser = GetUserId();
 	new_rte->requiredPerms = view_rte->requiredPerms;
 
 	/*
diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c
index eebc493..513a2dd 100644
--- a/src/backend/rewrite/rowsecurity.c
+++ b/src/backend/rewrite/rowsecurity.c
@@ -105,7 +105,8 @@ row_security_policy_hook_type row_security_policy_hook_restrictive = NULL;
 void
 get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
 						  List **securityQuals, List **withCheckOptions,
-						  bool *hasRowSecurity, bool *hasSubLinks)
+						  bool *hasRowSecurity, bool *hasSubLinks,
+						  bool security_definer_view)
 {
 	Oid			user_id;
 	int			rls_status;
@@ -125,10 +126,13 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
 		return;
 
 	/* Switch to checkAsUser if it's set */
-	user_id = rte->checkAsUser ? rte->checkAsUser : GetUserId();
+	if (security_definer_view)
+		user_id = rte->checkAsUser ? rte->checkAsUser : GetUserId();
+	else
+		user_id = GetUserId();
 
 	/* Determine the state of RLS for this, pass checkAsUser explicitly */
-	rls_status = check_enable_rls(rte->relid, rte->checkAsUser, false);
+	rls_status = check_enable_rls(rte->relid, user_id, false);
 
 	/* If there is no RLS on this table at all, nothing to do */
 	if (rls_status == RLS_NONE)
diff --git a/src/include/rewrite/rowsecurity.h b/src/include/rewrite/rowsecurity.h
index 4af244d..0aabf3d 100644
--- a/src/include/rewrite/rowsecurity.h
+++ b/src/include/rewrite/rowsecurity.h
@@ -43,6 +43,7 @@ extern PGDLLIMPORT row_security_policy_hook_type row_security_policy_hook_restri
 extern void get_row_security_policies(Query *root,
 						  RangeTblEntry *rte, int rt_index,
 						  List **securityQuals, List **withCheckOptions,
-						  bool *hasRowSecurity, bool *hasSubLinks);
+						  bool *hasRowSecurity, bool *hasSubLinks,
+						  bool security_definer_view);
 
 #endif   /* ROWSECURITY_H */
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 8a55a09..da248e3 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -265,6 +265,7 @@ typedef struct ViewOptions
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	bool		security_barrier;
+	bool		security_definer;
 	int			check_option_offset;
 } ViewOptions;
 
@@ -278,6 +279,14 @@ typedef struct ViewOptions
 	 ((ViewOptions *) (relation)->rd_options)->security_barrier : false)
 
 /*
+ * RelationIsSecurityDefiner
+ *		Returns whether the relation is security definer, or not.
+ */
+#define RelationIsSecurityDefinerView(relation)	\
+	((relation)->rd_options ?				\
+	 ((ViewOptions *) (relation)->rd_options)->security_definer : false)
+
+/*
  * RelationHasCheckOption
  *		Returns true if the relation is a view defined with either the local
  *		or the cascaded check option.  Note multiple eval of argument!
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 8d925dc..d1f5742 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1425,7 +1425,7 @@ CREATE POLICY p1 ON b1 USING (a % 2 = 0);
 ALTER TABLE b1 ENABLE ROW LEVEL SECURITY;
 GRANT ALL ON b1 TO rls_regress_user1;
 SET SESSION AUTHORIZATION rls_regress_user1;
-CREATE VIEW bv1 WITH (security_barrier) AS SELECT * FROM b1 WHERE a > 0 WITH CHECK OPTION;
+CREATE VIEW bv1 WITH (security_barrier, security_definer) AS SELECT * FROM b1 WHERE a > 0 WITH CHECK OPTION;
 GRANT ALL ON bv1 TO rls_regress_user2;
 SET SESSION AUTHORIZATION rls_regress_user2;
 EXPLAIN (COSTS OFF) SELECT * FROM bv1 WHERE f_leak(b);
@@ -1892,7 +1892,7 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test3;
 --
 -- View and Table owner are the same.
 SET SESSION AUTHORIZATION rls_regress_user0;
-CREATE VIEW rls_view AS SELECT * FROM z1 WHERE f_leak(b);
+CREATE VIEW rls_view WITH (security_definer) AS SELECT * FROM z1 WHERE f_leak(b);
 GRANT SELECT ON rls_view TO rls_regress_user1;
 -- Query as role that is not owner of view or table.  Should return all records.
 SET SESSION AUTHORIZATION rls_regress_user1;
@@ -1941,7 +1941,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM rls_view;
 DROP VIEW rls_view;
 -- View and Table owners are different.
 SET SESSION AUTHORIZATION rls_regress_user1;
-CREATE VIEW rls_view AS SELECT * FROM z1 WHERE f_leak(b);
+CREATE VIEW rls_view WITH (security_definer) AS SELECT * FROM z1 WHERE f_leak(b);
 GRANT SELECT ON rls_view TO rls_regress_user0;
 -- Query as role that is not owner of view but is owner of table.
 -- Should return records based on view owner policies.
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 6c71371..b62f1ad 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -966,7 +966,7 @@ CREATE USER view_user2;
 SET SESSION AUTHORIZATION view_user1;
 CREATE TABLE base_tbl(a int, b text, c float);
 INSERT INTO base_tbl VALUES (1, 'Row 1', 1.0);
-CREATE VIEW rw_view1 AS SELECT b AS bb, c AS cc, a AS aa FROM base_tbl;
+CREATE VIEW rw_view1 WITH (security_definer) AS SELECT b AS bb, c AS cc, a AS aa FROM base_tbl;
 INSERT INTO rw_view1 VALUES ('Row 2', 2.0, 2);
 GRANT SELECT ON base_tbl TO view_user2;
 GRANT SELECT ON rw_view1 TO view_user2;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index decde90..817ade7 100644
--- a/src/test/regress/sql/rowsecurity.sql
+++ b/src/test/regress/sql/rowsecurity.sql
@@ -491,7 +491,7 @@ ALTER TABLE b1 ENABLE ROW LEVEL SECURITY;
 GRANT ALL ON b1 TO rls_regress_user1;
 
 SET SESSION AUTHORIZATION rls_regress_user1;
-CREATE VIEW bv1 WITH (security_barrier) AS SELECT * FROM b1 WHERE a > 0 WITH CHECK OPTION;
+CREATE VIEW bv1 WITH (security_barrier, security_definer) AS SELECT * FROM b1 WHERE a > 0 WITH CHECK OPTION;
 GRANT ALL ON bv1 TO rls_regress_user2;
 
 SET SESSION AUTHORIZATION rls_regress_user2;
@@ -687,7 +687,7 @@ EXPLAIN (COSTS OFF) EXECUTE plancache_test3;
 --
 -- View and Table owner are the same.
 SET SESSION AUTHORIZATION rls_regress_user0;
-CREATE VIEW rls_view AS SELECT * FROM z1 WHERE f_leak(b);
+CREATE VIEW rls_view WITH (security_definer) AS SELECT * FROM z1 WHERE f_leak(b);
 GRANT SELECT ON rls_view TO rls_regress_user1;
 
 -- Query as role that is not owner of view or table.  Should return all records.
@@ -703,7 +703,7 @@ DROP VIEW rls_view;
 
 -- View and Table owners are different.
 SET SESSION AUTHORIZATION rls_regress_user1;
-CREATE VIEW rls_view AS SELECT * FROM z1 WHERE f_leak(b);
+CREATE VIEW rls_view WITH (security_definer) AS SELECT * FROM z1 WHERE f_leak(b);
 GRANT SELECT ON rls_view TO rls_regress_user0;
 
 -- Query as role that is not owner of view but is owner of table.
diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql
index 5297a71..8452c18 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -397,7 +397,7 @@ CREATE USER view_user2;
 SET SESSION AUTHORIZATION view_user1;
 CREATE TABLE base_tbl(a int, b text, c float);
 INSERT INTO base_tbl VALUES (1, 'Row 1', 1.0);
-CREATE VIEW rw_view1 AS SELECT b AS bb, c AS cc, a AS aa FROM base_tbl;
+CREATE VIEW rw_view1 WITH (security_definer) AS SELECT b AS bb, c AS cc, a AS aa FROM base_tbl;
 INSERT INTO rw_view1 VALUES ('Row 2', 2.0, 2);
 
 GRANT SELECT ON base_tbl TO view_user2;
