/*NO QUERY CACHE*/コメントで始まるSELECT
システムカタログを使用しているSELECT
TABLESAMPLEを使っているSELECT
+ 行セキュリティが設定されているテーブルを使っているSELECT
</programlisting>
ただし、VIEWと unloggedテーブルは、cache_safe_memqcache_table_list に記載することでキャッシュされます。
</para>
</note>
+
+ <note>
+ <para>
+ 以下のコマンドはクエリキャッシュとデータベース内容の整合性を失わせる可能性があるので、実行されるとクエリキャッシュをすべて削除します。
+ <programlisting>
+ ALTER DATABASE
+ ALTER ROLE
+ ALTER TABLE
+ REVOKE
+ </programlisting>
+ また、SET ROLE、SET SESSION AUTHORIZATIONが実行されると、そのセッション内ではクエリキャッシュは使用されず、また新たにクエリキャッシュが作成されることもありません。
+ <productname>Pgpool-II</productname>はセッションユーザが異なるとクエリキャッシュを違うものと見なしますが、一方で<productname>PostgreSQL</productname>のアクセス権管理はカレントユーザ(current user)を基準に行っており、これらのコマンドはクエリキャッシュとPostgreSQLのアクセス権管理の間の整合性を損なう可能性があるからです。
+ ただし、更新クエリによるクエリキャッシュの削除はこれらのコマンドが使われていない場合と同様に行われます。
+ </para>
+ </note>
+
<para>
<!--
In memory cache saves the pair of SELECT statement
SELECT starting with "/*NO QUERY CACHE*/" comment
SELECT including system catalogs
SELECT uses TABLESAMPLE
+ SELECT uses row security enabled tables
</programlisting>
However, VIEWs and SELECTs accessing unlogged tables can be
cached by specifying in
</para>
</note>
+ <note>
+ <para>
+ Since consistency between the query cache and database content can
+ be lost by following commands, the query cache is all deleted if
+ they are executed:
+ <programlisting>
+ ALTER DATABASE
+ ALTER ROLE
+ ALTER TABLE
+ REVOKE
+ </programlisting>
+ Moreover, if SET ROLE or SET SESSION AUTHORIZATION are executed,
+ the query cache will not be used and new cache will not be created
+ in the session.
+ <productname>Pgpool-II</productname> assumes that two query cache
+ are different if their session users are different. On the other
+ hand, <productname>PostgreSQL</productname> manages access control
+ depending on current user. Thus these commands may break the
+ consistency between these two access controls. However, cache
+ invalidation by update commands are performed in the same way in
+ that these commands are not used.
+ </para>
+ </note>
+
<para>
On the other hand, it might be slower than the normal path
in some cases, because it adds some overhead to store cache.
dml_adaptive_init();
unset_tx_started_by_multi_statement_query();
+
+ unset_query_cache_disabled();
+
+ unset_query_cache_disabled_tx();
}
/*
session_context->is_tx_started_by_multi_statement = false;
}
+
+/*
+ * Set query_cache_disabled
+ */
+void
+set_query_cache_disabled(void)
+{
+ if (!session_context)
+ ereport(ERROR,
+ (errmsg("set_query_cache_disabled: session context is not initialized")));
+
+ session_context->query_cache_disabled = true;
+}
+
+/*
+ * Unset query_cache_disabled
+ */
+void
+unset_query_cache_disabled(void)
+{
+ if (!session_context)
+ ereport(ERROR,
+ (errmsg("unset_query_cache_disabled: session context is not initialized")));
+
+ session_context->query_cache_disabled = false;
+}
+
+/*
+ * Get query_cache_disabled
+ */
+bool
+query_cache_disabled(void)
+{
+ if (!session_context)
+ ereport(ERROR,
+ (errmsg("query_cache_disabled: session context is not initialized")));
+
+ return session_context->query_cache_disabled ||
+ session_context->query_cache_disabled_tx;
+}
+
+/*
+ * Set query_cache_disabled in transaction
+ */
+void
+set_query_cache_disabled_tx(void)
+{
+ if (!session_context)
+ ereport(ERROR,
+ (errmsg("set_query_cache_disabled_tx: session context is not initialized")));
+
+ session_context->query_cache_disabled_tx = true;
+}
+
+/*
+ * Unset query_cache_disabled in transaction
+ */
+void
+unset_query_cache_disabled_tx(void)
+{
+ if (!session_context)
+ ereport(ERROR,
+ (errmsg("unset_query_cache_disabled_tx: session context is not initialized")));
+
+ session_context->query_cache_disabled_tx = false;
+}
+
+/*
+ * Get query_cache_disabled in transaction
+ */
+bool
+query_cache_disabled_tx(void)
+{
+ if (!session_context)
+ ereport(ERROR,
+ (errmsg("query_cache_disabled_tx: session context is not initialized")));
+
+ return session_context->query_cache_disabled_tx;
+}
SI_SNAPSHOT_PREPARED
} SI_STATE;
+
/*
* Per session context:
*/
* transaction has been
* started by a
* multi-statement-query */
+ /*
+ * True if query cache feature disabled until session ends.
+ * This is set when SET ROLE/SET SESSION AUTHORIZATION executed.
+ */
+ bool query_cache_disabled;
+ /*
+ * True if query cache feature disabled until current transaction ends.
+ * This is set when REVOKE executed in a transaction.
+ */
+ bool query_cache_disabled_tx;
+
} POOL_SESSION_CONTEXT;
extern void pool_init_session_context(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend);
extern void set_tx_started_by_multi_statement_query(void);
extern void unset_tx_started_by_multi_statement_query(void);
+extern void set_query_cache_disabled(void);
+extern void unset_query_cache_disabled(void);
+extern bool query_cache_disabled(void);
+extern void set_query_cache_disabled_tx(void);
+extern void unset_query_cache_disabled_tx(void);
+extern bool query_cache_disabled_tx(void);
+
#endif /* POOL_SESSION_CONTEXT_H */
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2023 PgPool Global Development Group
+ * Copyright (c) 2003-2024 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
extern void pool_init_whole_cache_blocks(void);
+extern int delete_all_cache_on_memcached(void);
+
#endif /* POOL_MEMQCACHE_H */
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2023 PgPool Global Development Group
+ * Copyright (c) 2003-2024 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
bool has_insertinto_or_locking_clause; /* True if it has SELECT
* INTO or FOR
* SHARE/UPDATE */
+ bool row_security; /* true if row security enabled */
int num_oids; /* number of oids */
int table_oids[POOL_MAX_SELECT_OIDS]; /* table oids */
char table_names[POOL_MAX_SELECT_OIDS][NAMEDATALEN]; /* table names */
extern void discard_temp_table_relcache(void);
extern bool pool_has_unlogged_table(Node *node);
extern bool pool_has_view(Node *node);
+extern bool pool_has_row_security(Node *node);
extern bool pool_has_insertinto_or_locking_clause(Node *node);
extern bool pool_has_pgpool_regclass(void);
extern bool pool_has_to_regclass(void);
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2023 PgPool Global Development Group
+ * Copyright (c) 2003-2024 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
static int forward_command_complete(POOL_CONNECTION * frontend, char *packet, int packetlen);
static int forward_empty_query(POOL_CONNECTION * frontend, char *packet, int packetlen);
static int forward_packet_to_frontend(POOL_CONNECTION * frontend, char kind, char *packet, int packetlen);
+static void process_clear_cache(POOL_CONNECTION_POOL * backend);
+static void clear_query_cache(void);
POOL_STATUS
CommandComplete(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend, bool command_complete)
/* Forget a transaction was started by multi statement query */
unset_tx_started_by_multi_statement_query();
+
+ /*
+ * Query cache enabled and REVOKE was issued in this transaction?
+ */
+ if (pool_config->memory_cache_enabled &&
+ query_cache_disabled_tx())
+ {
+ /*
+ * Clear all the query cache.
+ */
+ clear_query_cache();
+
+ /* Unset query cache disabled in this transaction */
+ unset_query_cache_disabled_tx();
+ }
}
else if (stmt->kind == TRANS_STMT_ROLLBACK)
{
/* Forget a transaction was started by multi statement query */
unset_tx_started_by_multi_statement_query();
+
+ /* Unset query cache disabled in this transaction */
+ unset_query_cache_disabled_tx();
}
}
else if (IsA(node, CreateStmt))
}
}
}
+ else if (IsA(node, VariableSetStmt))
+ {
+ VariableSetStmt *stmt = (VariableSetStmt *) node;
+
+ /* SET ROLE or SESSION AUTHORIZATION command? */
+ if (stmt->kind == VAR_SET_VALUE &&
+ (!strcmp(stmt->name, "role") ||
+ !strcmp(stmt->name, "session_authorization")))
+ /* disable query cache in this session */
+ set_query_cache_disabled();
+ }
+ else if (IsA(node, GrantStmt))
+ {
+ GrantStmt *stmt = (GrantStmt *) node;
+
+ /* REVOKE? */
+ if (stmt->is_grant)
+ return;
+
+ /* Clear query cache */
+ process_clear_cache(backend);
+ }
+ else if (IsA(node, AlterTableStmt) || IsA(node, AlterDatabaseStmt) ||
+ IsA(node, AlterDatabaseSetStmt) || IsA(node, AlterRoleStmt))
+ {
+ /* Clear query cache */
+ process_clear_cache(backend);
+ }
}
/*
return 0;
}
+
+/*
+ * Process statements that need clearing query cache
+ */
+static void
+process_clear_cache(POOL_CONNECTION_POOL * backend)
+{
+ /* Query cache enabled? */
+ if (!pool_config->memory_cache_enabled)
+ return;
+
+ /* Streaming replication mode? */
+ if (SL_MODE)
+ {
+ /*
+ * Are we inside a transaction?
+ */
+ if (TSTATE(backend, MAIN_NODE_ID ) == 'T')
+ {
+ /*
+ * Disable query cache in this transaction.
+ * All query cache will be cleared at commit.
+ */
+ set_query_cache_disabled_tx();
+ }
+ else if (TSTATE(backend, MAIN_NODE_ID ) == 'I') /* outside transaction */
+ {
+ /*
+ * Clear all the query cache.
+ */
+ clear_query_cache();
+ }
+ }
+ else
+ {
+ /*
+ * Are we inside a transaction?
+ */
+ if (TSTATE(backend, MAIN_NODE_ID ) == 'T')
+ {
+ /* Inside user started transaction? */
+ if (!INTERNAL_TRANSACTION_STARTED(backend, MAIN_NODE_ID))
+ {
+ /*
+ * Disable query cache in this transaction.
+ * All query cache will be cleared at commit.
+ */
+ set_query_cache_disabled_tx();
+ }
+ else
+ {
+ /*
+ * Clear all the query cache.
+ */
+ clear_query_cache();
+ }
+ }
+ else if (TSTATE(backend, MAIN_NODE_ID ) == 'I') /* outside transaction */
+ {
+ /*
+ * Clear all the query cache.
+ */
+ clear_query_cache();
+ }
+ }
+}
+
+/*
+ * Clear query cache on shmem or memcached
+ */
+static
+void clear_query_cache(void)
+{
+ /*
+ * Clear all the shared memory cache and oid maps.
+ */
+ if (pool_is_shmem_cache())
+ {
+ pool_clear_memory_cache();
+ ereport(LOG,
+ (errmsg("all query cache in shared memory deleted")));
+ }
+ else
+#ifdef USE_MEMCACHED
+ {
+ /*
+ * Clear all the memcached cache and oid maps.
+ */
+ delete_all_cache_on_memcached();
+ pool_discard_oid_maps();
+ ereport(LOG,
+ (errmsg("all query cache in memcached deleted")));
+ }
+#else
+ {
+ ereport(WARNING,
+ (errmsg("failed to clear cache on memcached, memcached support is not enabled")));
+ }
+#endif
+}
* catalog, which will add significant overhead. Moreover if we are in
* aborted transaction, commands should be ignored, so we should not use
* query cache.
+ * Also query cache is disabled, we should not fetch from query cache.
*/
if (pool_config->memory_cache_enabled && is_likely_select &&
!pool_is_writing_transaction() &&
- TSTATE(backend, MAIN_REPLICA ? PRIMARY_NODE_ID : REAL_MAIN_NODE_ID) != 'E')
+ TSTATE(backend, MAIN_REPLICA ? PRIMARY_NODE_ID : REAL_MAIN_NODE_ID) != 'E' &&
+ !query_cache_disabled())
{
bool foundp;
*/
if (pool_config->memory_cache_enabled && !pool_is_writing_transaction() &&
(TSTATE(backend, MAIN_REPLICA ? PRIMARY_NODE_ID : REAL_MAIN_NODE_ID) != 'E')
- && pool_is_likely_select(query))
+ && pool_is_likely_select(query) && !query_cache_disabled())
{
POOL_STATUS status;
char *search_query = NULL;
}
}
+ /*
+ * If SELECT uses row security enabled tables, it's not allowed to cache.
+ */
+ if (pool_has_row_security(node))
+ return false;
/*
* If the table is in the cache_safe_memqcache_table_list, allow to cache
POOL_SETMASK(&oldmask);
}
+#ifdef USE_MEMCACHED
+/*
+ * delete all query cache on memcached
+ */
+int
+delete_all_cache_on_memcached(void)
+{
+ memcached_return rc;
+
+ rc = memcached_flush(memc, 0);
+
+ /* delete all cache on memcached */
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
+ {
+ ereport(LOG,
+ (errmsg("failed to delete all cache on memcached, error:\"%s\"", memcached_strerror(memc, rc))));
+ return 0;
+ }
+ return 1;
+}
+#endif
+
/*
* Return shared memory cache address
*/
session_context = pool_get_session_context(true);
/* Ok to cache SELECT result? */
- if (pool_is_cache_safe())
+ if (pool_is_cache_safe() && !query_cache_disabled())
{
SelectContext ctx;
MemoryContext old_context;
--- /dev/null
+# Testing ALTER DATABASE
+# create cache
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# execute ALTER DATABASE
+'P' "" "ALTER DATABASE test2 RESET ALL"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache is not used
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# explicit transaction case
+'P' "" "BEGIN"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "ALTER DATABASE test2 RESET ALL"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache is not used
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "END"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache is used
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# ALTER DATABASE is executed on another session case
+# Make sure to create cache (sync needed)
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "ALTER DATABASE test2 RESET ALL"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# ALTER DATABASE is executed on another session case
+# Make sure this does not access cache
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# ALTER ROLE BYPASSRLS case
+# Make sure to create cache (sync needed)
+'P' "" "SELECT * FROM users"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM users"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "ALTER ROLE foo BYPASSRLS"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# expect to ignore cache and result is all rows
+'P' "" "SELECT * FROM users"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "RESET ROLE"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "ALTER ROLE foo NOBYPASSRLS"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# expect to ignore cache and result is one row
+'P' "" "SELECT * FROM users"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# ALTER ROLE BYPASSRLS case
+# Make sure to create cache (sync needed)
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'P' "" "ALTER TABLE t1 ADD COLUMN j INT"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache is not used
+'P' "" "SELECT j FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# explicit transaction case
+'P' "" "BEGIN"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "ALTER TABLE t1 DROP COLUMN j"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache is not used (an error expected)
+'P' "" "SELECT i,j FROM t1"
+#'B' "" "" 0 0 0
+#'E' "" 0
+'S'
+'Y'
+'P' "" "END"
+'B' "" "" 0 0 0
+'E' "" 0
+# Sync is needed to reset query_cache_disabled_tx flag
+'S'
+'Y'
+# create cache
+'P' "" "SELECT j FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache is used
+'P' "" "SELECT j FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# drop column j for subsequent test
+'Q' "ALTER TABLE t1 DROP COLUMN j"
+'S'
+'X'
--- /dev/null
+# ALTER TABLE is executed on another session case
+# Make sure to create cache (sync needed)
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "ALTER TABLE t1 ADD COLUMN j INT"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# ALTER TABLE is executed on another session case
+# Make sure this does not access cache
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+--
+-- testing an effect on a row level security enabled table and SET ROLE
+--
+CREATE TABLE users (user_name TEXT, data TEXT);
+NOTICE: DB node id: 0 statement: CREATE TABLE users (user_name TEXT, data TEXT);
+CREATE TABLE
+INSERT INTO users VALUES('foo', 'foodata');
+NOTICE: DB node id: 0 statement: INSERT INTO users VALUES('foo', 'foodata');
+INSERT 0 1
+INSERT INTO users VALUES('bar', 'bardata');
+NOTICE: DB node id: 0 statement: INSERT INTO users VALUES('bar', 'bardata');
+INSERT 0 1
+ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+NOTICE: DB node id: 0 statement: ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+ALTER TABLE
+CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+NOTICE: DB node id: 0 statement: CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+CREATE POLICY
+GRANT SELECT ON users TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON users TO foo;
+GRANT
+GRANT SELECT ON users TO bar;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON users TO bar;
+GRANT
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- run SELECT as foo. Only user_name = 'foo' data expected.
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+(1 row)
+
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+SET ROLE TO bar;
+NOTICE: DB node id: 0 statement: SET ROLE TO bar;
+SET
+-- run SELECT as bar. Only user_name = 'bar' data expected.
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ bar | bardata
+(1 row)
+
+--
+-- testing row security with row_security = off
+--
+SET ROW_SECURITY TO off;
+NOTICE: DB node id: 0 statement: SET ROW_SECURITY TO off;
+SET
+-- Error expected
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ERROR: query would be affected by row-level security policy for table "users"
+--
+-- testing SET ROLE
+--
+CREATE TABLE footable(t text);
+NOTICE: DB node id: 0 statement: CREATE TABLE footable(t text);
+CREATE TABLE
+INSERT INTO footable VALUES('foo');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES('foo');
+INSERT 0 1
+GRANT SELECT ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON footable TO foo;
+GRANT
+GRANT INSERT ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT INSERT ON footable TO foo;
+GRANT
+GRANT UPDATE ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT UPDATE ON footable TO foo;
+GRANT
+GRANT DELETE ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT DELETE ON footable TO foo;
+GRANT
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+SET ROLE TO bar;
+NOTICE: DB node id: 0 statement: SET ROLE TO bar;
+SET
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ERROR: permission denied for table footable
+--
+-- testing SESSION AUTHORIZATION
+--
+SET SESSION AUTHORIZATION bar;
+NOTICE: DB node id: 0 statement: SET SESSION AUTHORIZATION bar;
+SET
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ERROR: permission denied for table footable
+--
+-- testing SET ROLE. Make sure that query cache is not
+-- created.
+--
+-- create cache
+SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo1');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo1');
+INSERT 0 1
+-- restore ROLE
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+--
+-- explicit transaction case
+--
+-- create cache
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo2');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo2');
+INSERT 0 1
+END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+--
+-- explicit transaction abort case
+--
+-- create cache
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 0 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo3');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo3');
+INSERT 0 1
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+ foo3
+(4 rows)
+
+ABORT;
+NOTICE: DB node id: 0 statement: ABORT;
+ROLLBACK
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+--
+-- Testing REVOKE
+--
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo;
+REVOKE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- Make sure foo cannot SELECT t1
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ERROR: permission denied for table t1
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+-- GRANT again
+GRANT SELECT ON t1 TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON t1 TO foo;
+GRANT
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo;
+REVOKE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- Make sure foo cannot SELECT t1
+-- (thus REVOKE will be rollbacked )
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ERROR: permission denied for table t1
+END;
+NOTICE: DB node id: 0 statement: END;
+ROLLBACK
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- because REVOKE is rolled back, foo should be able to access t1
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- REVOKE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- execute REVOKE
+REVOKE SELECT ON t1 FROM foo
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo
+REVOKE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- ALTER ROLE BYPASSRLS case
+--
+ALTER ROLE foo BYPASSRLS;
+NOTICE: DB node id: 0 statement: ALTER ROLE foo BYPASSRLS;
+ALTER ROLE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- expect to ignore cache and result is all rows
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+ bar | bardata
+(2 rows)
+
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+ALTER ROLE foo NOBYPASSRLS;
+NOTICE: DB node id: 0 statement: ALTER ROLE foo NOBYPASSRLS;
+ALTER ROLE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- expect to ignore cache and result is one row
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+(1 row)
+
+--
+-- Testing ALTER TABLE
+--
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 DROP COLUMN j;
+ALTER TABLE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- Make sure cache is used
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- ALTER TABLE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 DROP COLUMN j;
+ALTER TABLE
+--
+-- Testing ALTER DATABASE
+--
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- create taget database
+create database test2;
+NOTICE: DB node id: 0 statement: create database test2;
+CREATE DATABASE
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- Make sure cache is used
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+--
+-- ALTER DATABASE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
--- /dev/null
+--
+-- testing an effect on a row level security enabled table and SET ROLE
+--
+CREATE TABLE users (user_name TEXT, data TEXT);
+NOTICE: DB node id: 0 statement: CREATE TABLE users (user_name TEXT, data TEXT);
+NOTICE: DB node id: 1 statement: CREATE TABLE users (user_name TEXT, data TEXT);
+CREATE TABLE
+INSERT INTO users VALUES('foo', 'foodata');
+NOTICE: DB node id: 0 statement: INSERT INTO users VALUES('foo', 'foodata');
+NOTICE: DB node id: 1 statement: INSERT INTO users VALUES('foo', 'foodata');
+INSERT 0 1
+INSERT INTO users VALUES('bar', 'bardata');
+NOTICE: DB node id: 0 statement: INSERT INTO users VALUES('bar', 'bardata');
+NOTICE: DB node id: 1 statement: INSERT INTO users VALUES('bar', 'bardata');
+INSERT 0 1
+ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+NOTICE: DB node id: 0 statement: ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+NOTICE: DB node id: 1 statement: ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+ALTER TABLE
+CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+NOTICE: DB node id: 0 statement: CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+NOTICE: DB node id: 1 statement: CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+CREATE POLICY
+GRANT SELECT ON users TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON users TO foo;
+NOTICE: DB node id: 1 statement: GRANT SELECT ON users TO foo;
+GRANT
+GRANT SELECT ON users TO bar;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON users TO bar;
+NOTICE: DB node id: 1 statement: GRANT SELECT ON users TO bar;
+GRANT
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- run SELECT as foo. Only user_name = 'foo' data expected.
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+(1 row)
+
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+NOTICE: DB node id: 1 statement: RESET ROLE;
+RESET
+SET ROLE TO bar;
+NOTICE: DB node id: 0 statement: SET ROLE TO bar;
+NOTICE: DB node id: 1 statement: SET ROLE TO bar;
+SET
+-- run SELECT as bar. Only user_name = 'bar' data expected.
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ bar | bardata
+(1 row)
+
+--
+-- testing row security with row_security = off
+--
+SET ROW_SECURITY TO off;
+NOTICE: DB node id: 0 statement: SET ROW_SECURITY TO off;
+NOTICE: DB node id: 1 statement: SET ROW_SECURITY TO off;
+SET
+-- Error expected
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ERROR: query would be affected by row-level security policy for table "users"
+--
+-- testing SET ROLE
+--
+CREATE TABLE footable(t text);
+NOTICE: DB node id: 0 statement: CREATE TABLE footable(t text);
+NOTICE: DB node id: 1 statement: CREATE TABLE footable(t text);
+CREATE TABLE
+INSERT INTO footable VALUES('foo');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES('foo');
+NOTICE: DB node id: 1 statement: INSERT INTO footable VALUES('foo');
+INSERT 0 1
+GRANT SELECT ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON footable TO foo;
+NOTICE: DB node id: 1 statement: GRANT SELECT ON footable TO foo;
+GRANT
+GRANT INSERT ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT INSERT ON footable TO foo;
+NOTICE: DB node id: 1 statement: GRANT INSERT ON footable TO foo;
+GRANT
+GRANT UPDATE ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT UPDATE ON footable TO foo;
+NOTICE: DB node id: 1 statement: GRANT UPDATE ON footable TO foo;
+GRANT
+GRANT DELETE ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT DELETE ON footable TO foo;
+NOTICE: DB node id: 1 statement: GRANT DELETE ON footable TO foo;
+GRANT
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+SET ROLE TO bar;
+NOTICE: DB node id: 0 statement: SET ROLE TO bar;
+NOTICE: DB node id: 1 statement: SET ROLE TO bar;
+SET
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ERROR: permission denied for table footable
+--
+-- testing SESSION AUTHORIZATION
+--
+SET SESSION AUTHORIZATION bar;
+NOTICE: DB node id: 0 statement: SET SESSION AUTHORIZATION bar;
+NOTICE: DB node id: 1 statement: SET SESSION AUTHORIZATION bar;
+SET
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ERROR: permission denied for table footable
+--
+-- testing SET ROLE. Make sure that query cache is not
+-- created.
+--
+-- create cache
+SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo1');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo1');
+NOTICE: DB node id: 1 statement: INSERT INTO footable VALUES ('foo1');
+INSERT 0 1
+-- restore ROLE
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+NOTICE: DB node id: 1 statement: RESET ROLE;
+RESET
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+--
+-- explicit transaction case
+--
+-- create cache
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+NOTICE: DB node id: 1 statement: BEGIN;
+BEGIN
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo2');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo2');
+NOTICE: DB node id: 1 statement: INSERT INTO footable VALUES ('foo2');
+INSERT 0 1
+END;
+NOTICE: DB node id: 1 statement: END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+--
+-- explicit transaction abort case
+--
+-- create cache
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+NOTICE: DB node id: 1 statement: BEGIN;
+BEGIN
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 0 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo3');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo3');
+NOTICE: DB node id: 1 statement: INSERT INTO footable VALUES ('foo3');
+INSERT 0 1
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+ foo3
+(4 rows)
+
+ABORT;
+NOTICE: DB node id: 1 statement: ABORT;
+NOTICE: DB node id: 0 statement: ABORT;
+ROLLBACK
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+--
+-- Testing REVOKE
+--
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 1 statement: REVOKE SELECT ON t1 FROM foo;
+REVOKE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- Make sure foo cannot SELECT t1
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ERROR: permission denied for table t1
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+NOTICE: DB node id: 1 statement: RESET ROLE;
+RESET
+-- GRANT again
+GRANT SELECT ON t1 TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON t1 TO foo;
+NOTICE: DB node id: 1 statement: GRANT SELECT ON t1 TO foo;
+GRANT
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+NOTICE: DB node id: 1 statement: BEGIN;
+BEGIN
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 1 statement: REVOKE SELECT ON t1 FROM foo;
+REVOKE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- Make sure foo cannot SELECT t1
+-- (thus REVOKE will be rollbacked )
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ERROR: permission denied for table t1
+END;
+NOTICE: DB node id: 1 statement: END;
+NOTICE: DB node id: 0 statement: END;
+ROLLBACK
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- because REVOKE is rolled back, foo should be able to access t1
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- REVOKE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- execute REVOKE
+REVOKE SELECT ON t1 FROM foo
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo
+NOTICE: DB node id: 1 statement: REVOKE SELECT ON t1 FROM foo
+REVOKE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- ALTER ROLE BYPASSRLS case
+--
+ALTER ROLE foo BYPASSRLS;
+NOTICE: DB node id: 0 statement: ALTER ROLE foo BYPASSRLS;
+NOTICE: DB node id: 1 statement: ALTER ROLE foo BYPASSRLS;
+ALTER ROLE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- expect to ignore cache and result is all rows
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+ bar | bardata
+(2 rows)
+
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+NOTICE: DB node id: 1 statement: RESET ROLE;
+RESET
+ALTER ROLE foo NOBYPASSRLS;
+NOTICE: DB node id: 0 statement: ALTER ROLE foo NOBYPASSRLS;
+NOTICE: DB node id: 1 statement: ALTER ROLE foo NOBYPASSRLS;
+ALTER ROLE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+NOTICE: DB node id: 1 statement: SET ROLE TO foo;
+SET
+-- expect to ignore cache and result is one row
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+(1 row)
+
+--
+-- Testing ALTER TABLE
+--
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 1 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+NOTICE: DB node id: 1 statement: BEGIN;
+BEGIN
+ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 1 statement: ALTER TABLE t1 DROP COLUMN j;
+ALTER TABLE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+END;
+NOTICE: DB node id: 1 statement: END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- Make sure cache is used
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- ALTER TABLE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 1 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 1 statement: ALTER TABLE t1 DROP COLUMN j;
+ALTER TABLE
+--
+-- Testing ALTER DATABASE
+--
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 1 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- create taget database
+create database test2;
+NOTICE: DB node id: 0 statement: create database test2;
+NOTICE: DB node id: 1 statement: create database test2;
+CREATE DATABASE
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 1 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+NOTICE: DB node id: 1 statement: BEGIN;
+BEGIN
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 1 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+END;
+NOTICE: DB node id: 1 statement: END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- Make sure cache is used
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+--
+-- ALTER DATABASE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 1 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
--- /dev/null
+--
+-- testing an effect on a row level security enabled table and SET ROLE
+--
+CREATE TABLE users (user_name TEXT, data TEXT);
+NOTICE: DB node id: 0 statement: CREATE TABLE users (user_name TEXT, data TEXT);
+CREATE TABLE
+INSERT INTO users VALUES('foo', 'foodata');
+NOTICE: DB node id: 0 statement: INSERT INTO users VALUES('foo', 'foodata');
+INSERT 0 1
+INSERT INTO users VALUES('bar', 'bardata');
+NOTICE: DB node id: 0 statement: INSERT INTO users VALUES('bar', 'bardata');
+INSERT 0 1
+ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+NOTICE: DB node id: 0 statement: ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+ALTER TABLE
+CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+NOTICE: DB node id: 0 statement: CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+CREATE POLICY
+GRANT SELECT ON users TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON users TO foo;
+GRANT
+GRANT SELECT ON users TO bar;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON users TO bar;
+GRANT
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- run SELECT as foo. Only user_name = 'foo' data expected.
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+(1 row)
+
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+SET ROLE TO bar;
+NOTICE: DB node id: 0 statement: SET ROLE TO bar;
+SET
+-- run SELECT as bar. Only user_name = 'bar' data expected.
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ bar | bardata
+(1 row)
+
+--
+-- testing row security with row_security = off
+--
+SET ROW_SECURITY TO off;
+NOTICE: DB node id: 0 statement: SET ROW_SECURITY TO off;
+SET
+-- Error expected
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ERROR: query would be affected by row-level security policy for table "users"
+--
+-- testing SET ROLE
+--
+CREATE TABLE footable(t text);
+NOTICE: DB node id: 0 statement: CREATE TABLE footable(t text);
+CREATE TABLE
+INSERT INTO footable VALUES('foo');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES('foo');
+INSERT 0 1
+GRANT SELECT ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON footable TO foo;
+GRANT
+GRANT INSERT ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT INSERT ON footable TO foo;
+GRANT
+GRANT UPDATE ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT UPDATE ON footable TO foo;
+GRANT
+GRANT DELETE ON footable TO foo;
+NOTICE: DB node id: 0 statement: GRANT DELETE ON footable TO foo;
+GRANT
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+SET ROLE TO bar;
+NOTICE: DB node id: 0 statement: SET ROLE TO bar;
+SET
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ERROR: permission denied for table footable
+--
+-- testing SESSION AUTHORIZATION
+--
+SET SESSION AUTHORIZATION bar;
+NOTICE: DB node id: 0 statement: SET SESSION AUTHORIZATION bar;
+SET
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ERROR: permission denied for table footable
+--
+-- testing SET ROLE. Make sure that query cache is not
+-- created.
+--
+-- create cache
+SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+-----
+ foo
+(1 row)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo1');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo1');
+INSERT 0 1
+-- restore ROLE
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+--
+-- explicit transaction case
+--
+-- create cache
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+(2 rows)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo2');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo2');
+INSERT 0 1
+END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+--
+-- explicit transaction abort case
+--
+-- create cache
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- change role
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 0 statement: SELECT ..."
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo3');
+NOTICE: DB node id: 0 statement: INSERT INTO footable VALUES ('foo3');
+INSERT 0 1
+SELECT * FROM footable;
+NOTICE: DB node id: 0 statement: SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+ foo3
+(4 rows)
+
+ABORT;
+NOTICE: DB node id: 0 statement: ABORT;
+ROLLBACK
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+ t
+------
+ foo
+ foo1
+ foo2
+(3 rows)
+
+--
+-- Testing REVOKE
+--
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo;
+REVOKE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- Make sure foo cannot SELECT t1
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ERROR: permission denied for table t1
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+-- GRANT again
+GRANT SELECT ON t1 TO foo;
+NOTICE: DB node id: 0 statement: GRANT SELECT ON t1 TO foo;
+GRANT
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo;
+REVOKE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- Make sure foo cannot SELECT t1
+-- (thus REVOKE will be rollbacked )
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ERROR: permission denied for table t1
+END;
+NOTICE: DB node id: 0 statement: END;
+ROLLBACK
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- because REVOKE is rolled back, foo should be able to access t1
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- REVOKE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- execute REVOKE
+REVOKE SELECT ON t1 FROM foo
+NOTICE: DB node id: 0 statement: REVOKE SELECT ON t1 FROM foo
+REVOKE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- ALTER ROLE BYPASSRLS case
+--
+ALTER ROLE foo BYPASSRLS;
+NOTICE: DB node id: 0 statement: ALTER ROLE foo BYPASSRLS;
+ALTER ROLE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- expect to ignore cache and result is all rows
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+ bar | bardata
+(2 rows)
+
+RESET ROLE;
+NOTICE: DB node id: 0 statement: RESET ROLE;
+RESET
+ALTER ROLE foo NOBYPASSRLS;
+NOTICE: DB node id: 0 statement: ALTER ROLE foo NOBYPASSRLS;
+ALTER ROLE
+SET ROLE TO foo;
+NOTICE: DB node id: 0 statement: SET ROLE TO foo;
+SET
+-- expect to ignore cache and result is one row
+SELECT * FROM users;
+NOTICE: DB node id: 0 statement: SELECT * FROM users;
+ user_name | data
+-----------+---------
+ foo | foodata
+(1 row)
+
+--
+-- Testing ALTER TABLE
+--
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 DROP COLUMN j;
+ALTER TABLE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+-- Make sure cache is used
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+--
+-- ALTER TABLE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+SELECT * FROM t1;
+ i
+---
+ 2
+(1 row)
+
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER TABLE t1 DROP COLUMN j;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 DROP COLUMN j;
+ALTER TABLE
+--
+-- Testing ALTER DATABASE
+--
+ALTER TABLE t1 ADD COLUMN j INT;
+NOTICE: DB node id: 0 statement: ALTER TABLE t1 ADD COLUMN j INT;
+ALTER TABLE
+-- create taget database
+create database test2;
+NOTICE: DB node id: 0 statement: create database test2;
+CREATE DATABASE
+-- create cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- explicit transaction case
+BEGIN;
+NOTICE: DB node id: 0 statement: BEGIN;
+BEGIN
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure cache is not used
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+END;
+NOTICE: DB node id: 0 statement: END;
+COMMIT
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+-- Make sure cache is used
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+--
+-- ALTER DATABASE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
+ALTER DATABASE test2 RESET ALL;
+NOTICE: DB node id: 0 statement: ALTER DATABASE test2 RESET ALL;
+ALTER DATABASE
+-- Make sure this does not access cache
+SELECT * FROM t1;
+NOTICE: DB node id: 0 statement: SELECT * FROM t1;
+ i | j
+---+---
+ 2 |
+(1 row)
+
--- /dev/null
+# Testing REVOKE
+# create cache
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# revoke
+'P' "" "REVOKE SELECT ON t1 FROM foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# change role
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure foo cannot SELECT t1
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "RESET ROLE"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# GRANT again
+'P' "" "GRANT SELECT ON t1 TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# explicit transaction case
+'P' "" "BEGIN"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# execute REVOKE
+'P' "" "REVOKE SELECT ON t1 FROM foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# change role
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure foo cannot SELECT t1
+# (thus REVOKE will be rollbacked )
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "END"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# because REVOKE was rolled back, foo should be able to access t1
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# Testing REVOKE is executed on another session case
+# Make sure to create cache (sync needed)
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# execute REVOKE
+'P' "" "REVOKE SELECT ON t1 FROM foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# Testing REVOKE is executed on another session case
+# Make sure this does not access cache
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# run SELECT as foo. It is expected 0 row returned.
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM users WHERE user_name = 'bar'"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "RESET ROLE"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# run SELECT as bar. It is expected 0 row returned.
+'P' "" "SET ROLE TO bar"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM users WHERE user_name = 'foo'"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+#
+# testing row security with row_security = off
+# Error expected
+#
+'P' "" "SET row_security TO off"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "SELECT * FROM users"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# create query cache
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# SET SESSION_AUTHORIZATION
+'P' "" "SET SESSION AUTHORIZATION bar"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# run SELECT as bar. Permission denied is expected.
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# create query cache
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# SET ROLE
+'P' "" "SET ROLE TO bar"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# run SELECT as bar. Permission denied is expected.
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# create query cache
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# SET ROLE
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# run SELECT as foo to make sure that cache is not used.
+# If query cache was created we will NOT see
+# "NOTICE: DB node id: 1 statement: SELECT ..."
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Modify footable to see cache invalidation works even after SET ROLE.
+'P' "" "UPDATE footable SET t = 'foo1' WHERE t = 'foo1'"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# restore ROLE
+'P' "" "RESET ROLE"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Make sure cache was invalidated.
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
--- /dev/null
+# explicit transaction case
+# create query cache
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# change role
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "BEGIN"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# run SELECT as foo to make sure that cache is not used.
+# If query cache was created we will NOT see
+# "NOTICE: DB node id: 1 statement: SELECT ..."
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# Modify footable to see cache invalidation works even after SET ROLE.
+'P' "" "INSERT INTO footable VALUES ('foo3')"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'P' "" "END"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# undo the INSERT to not disturb subsequent tests
+'Q' "DELETE FROM footable WHERE t = 'foo3'"
+'Y'
+'X'
--- /dev/null
+# explicit transaction case
+# create cache
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+# change role
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+'P' "" "BEGIN"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+# run SELECT as foo to make sure that cache is not used.
+# If query cache was created we will NOT see
+# "NOTICE: DB node id: 0 statement: SELECT ..."
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+# Modify footable to see cache invalidation works even after SET ROLE.
+'P' "" "INSERT INTO footable VALUES ('foo3')"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+'P' "" "ABORT"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+# Make sure we don't see 'foo3' row.
+'P' "" "SELECT * FROM t1"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+# change role
+'P' "" "SET ROLE TO foo"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+'P' "" "BEGIN"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+# run SELECT as foo to make sure that cache is not used.
+# If query cache was created we will NOT see
+# "NOTICE: DB node id: 0 statement: SELECT ..."
+'P' "" "SELECT * FROM footable"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+# Modify footable to see cache invalidation works even after SET ROLE.
+'P' "" "INSERT INTO footable VALUES ('foo3')"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+
+'P' "" "ABORT"
+'B' "" "" 0 0 0
+'E' "" 0
+'S'
+'Y'
+'X'
TESTDIR=testdir
PSQL=$PGBIN/psql
+PGPROTO=$PGPOOL_INSTALL_DIR/bin/pgproto
+
+# remove error/notice details (message and so on) from
+# ErrorResponse or NoticeResponse messages.
+# used for pgproto.
+function del_details_from_error
+{
+ cat|sed -e '/ErrorResponse/s/ F .*//' -e '/NoticeResponse/s/ F .*$//'
+}
for mode in s r n
do
exit 1
fi
+ ./shutdownall
+ echo "backend_weight1 = 0" >> etc/pgpool.conf
+ echo "notice_per_node_statement = on" >> etc/pgpool.conf
+ ./startall
+ wait_for_pgpool_startup
+
+ createuser foo
+ createuser bar
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- testing an effect on a row level security enabled table and SET ROLE
+--
+CREATE TABLE users (user_name TEXT, data TEXT);
+INSERT INTO users VALUES('foo', 'foodata');
+INSERT INTO users VALUES('bar', 'bardata');
+ALTER TABLE users ENABLE ROW LEVEL SECURITY;
+CREATE POLICY user_policy ON users USING (user_name = CURRENT_USER);
+GRANT SELECT ON users TO foo;
+GRANT SELECT ON users TO bar;
+SET ROLE TO foo;
+-- run SELECT as foo. Only user_name = 'foo' data expected.
+SELECT * FROM users;
+RESET ROLE;
+SET ROLE TO bar;
+-- run SELECT as bar. Only user_name = 'bar' data expected.
+SELECT * FROM users;
+EOF
+
+#echo '=== extended query test for row security ===' >> result
+# $PGPROTO -d test -f ../row_security.data |& del_details_from_error >> result
+
+ $PSQL -a -U foo test >> result 2>&1 <<EOF
+--
+-- testing row security with row_security = off
+--
+SET ROW_SECURITY TO off;
+-- Error expected
+SELECT * FROM users;
+EOF
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- testing SET ROLE
+--
+CREATE TABLE footable(t text);
+INSERT INTO footable VALUES('foo');
+GRANT SELECT ON footable TO foo;
+GRANT INSERT ON footable TO foo;
+GRANT UPDATE ON footable TO foo;
+GRANT DELETE ON footable TO foo;
+SELECT * FROM footable;
+SET ROLE TO bar;
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+EOF
+
+#echo '==== extended query test for "testing SET ROLE" above ===' >> result
+# $PGPROTO -d test -f ../set_role1.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- testing SESSION AUTHORIZATION
+--
+SET SESSION AUTHORIZATION bar;
+-- run SELECT as bar. Permission denied is expected.
+SELECT * FROM footable;
+EOF
+
+#echo '=== extended query test for "testing SESSION AUTHORIZATION" above ===' >> result
+# $PGPROTO -d test -f ../session_authorization.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- testing SET ROLE. Make sure that query cache is not
+-- created.
+--
+-- create cache
+SELECT * FROM footable;
+-- change role
+SET ROLE TO foo;
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo1');
+-- restore ROLE
+RESET ROLE;
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+EOF
+
+#echo '=== extended query test for "testing SET ROLE" above ===' >> result
+# $PGPROTO -d test -f ../set_role2.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- explicit transaction case
+--
+-- create cache
+SELECT * FROM footable;
+SELECT * FROM footable;
+-- change role
+SET ROLE TO foo;
+BEGIN;
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 1 statement: SELECT ..."
+SELECT * FROM footable;
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo2');
+END;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- Make sure cache was invalidated.
+SELECT * FROM footable;
+EOF
+
+#echo '=== extended query test for "explicit transaction case" above ===' >> result
+# $PGPROTO -d test -f ../set_role3.data |& del_details_from_error >> result
+
+# $PSQL -a test >> result 2>&1 <<EOF
+#-- Make sure cache was invalidated.
+#SELECT * FROM footable;
+#EOF
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- explicit transaction abort case
+--
+-- create cache
+SELECT * FROM footable;
+SELECT * FROM footable;
+-- change role
+SET ROLE TO foo;
+BEGIN;
+-- run SELECT as foo to make sure that cache is not used.
+-- If query cache was created we will NOT see
+-- "NOTICE: DB node id: 0 statement: SELECT ..."
+SELECT * FROM footable;
+-- Modify footable to see cache invalidation works even after SET ROLE.
+INSERT INTO footable VALUES ('foo3');
+SELECT * FROM footable;
+ABORT;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+EOF
+
+#echo '=== extended query test for "explicit transaction abort case" above ===' >> result
+# $PGPROTO -d test -f ../set_role4.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+-- Make sure we don't see 'foo3' row.
+SELECT * FROM footable;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- Testing REVOKE
+--
+-- create cache
+SELECT * FROM t1;
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+SET ROLE TO foo;
+-- Make sure foo cannot SELECT t1
+SELECT * FROM t1;
+RESET ROLE;
+-- GRANT again
+GRANT SELECT ON t1 TO foo;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- explicit transaction case
+BEGIN;
+-- REVOKE
+REVOKE SELECT ON t1 FROM foo;
+SET ROLE TO foo;
+-- Make sure foo cannot SELECT t1
+-- (thus REVOKE will be rollbacked )
+SELECT * FROM t1;
+END;
+SET ROLE TO foo;
+-- because REVOKE is rolled back, foo should be able to access t1
+SELECT * FROM t1;
+EOF
+
+#echo '=== extended query test for "Tesing REVOKE" and "explicit transaction case" above ===' >> result
+# $PGPROTO -d test -f ../revoke1.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- REVOKE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+SELECT * FROM t1;
+-- execute REVOKE
+REVOKE SELECT ON t1 FROM foo
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- Make sure this does not access cache
+SELECT * FROM t1;
+EOF
+
+#echo '=== extended query test for "REVOKE is executed on another session case" above ===' >> result
+# $PGPROTO -d test -f ../revoke2.data |& del_details_from_error >> result
+# $PGPROTO -d test -f ../revoke3.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- ALTER ROLE BYPASSRLS case
+--
+ALTER ROLE foo BYPASSRLS;
+SET ROLE TO foo;
+-- expect to ignore cache and result is all rows
+SELECT * FROM users;
+RESET ROLE;
+ALTER ROLE foo NOBYPASSRLS;
+SET ROLE TO foo;
+-- expect to ignore cache and result is one row
+SELECT * FROM users;
+EOF
+
+#echo '=== extended query test for "ALTER ROLE BYPASSRLS case" case ===' >> result
+# $PGPROTO -d test -f ../alter_role.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- Testing ALTER TABLE
+--
+-- create cache
+SELECT * FROM t1;
+ALTER TABLE t1 ADD COLUMN j INT;
+-- Make sure cache is not used
+SELECT * FROM t1;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- explicit transaction case
+BEGIN;
+ALTER TABLE t1 DROP COLUMN j;
+-- Make sure cache is not used
+SELECT * FROM t1;
+END;
+SELECT * FROM t1;
+-- Make sure cache is used
+SELECT * FROM t1;
+EOF
+
+#echo '=== extended query test for "Testing ALTER TABLE and explicit transaction" case ===' >> result
+# $PGPROTO -d test -f ../alter_table1.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- ALTER TABLE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+SELECT * FROM t1;
+ALTER TABLE t1 ADD COLUMN j INT;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- Make sure this does not access cache
+SELECT * FROM t1;
+ALTER TABLE t1 DROP COLUMN j;
+EOF
+
+#echo '=== extended query test for "ALTER TABLE is executed on another session" case ===' >> result
+# $PGPROTO -d test -f ../alter_table2.data |& del_details_from_error >> result
+# $PGPROTO -d test -f ../alter_table3.data |& del_details_from_error >> result
+
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- Testing ALTER DATABASE
+--
+ALTER TABLE t1 ADD COLUMN j INT;
+-- create taget database
+create database test2;
+-- create cache
+SELECT * FROM t1;
+ALTER DATABASE test2 RESET ALL;
+-- Make sure cache is not used
+SELECT * FROM t1;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- explicit transaction case
+BEGIN;
+ALTER DATABASE test2 RESET ALL;
+-- Make sure cache is not used
+SELECT * FROM t1;
+END;
+SELECT * FROM t1;
+-- Make sure cache is used
+SELECT * FROM t1;
+EOF
+#echo '=== extended query test for "ALTER DATABSE and explicit transaction" case ===' >> result
+# $PGPROTO -d test -f ../alter_database1.data |& del_details_from_error >> result
+ $PSQL -a test >> result 2>&1 <<EOF
+--
+-- ALTER DATABASE is executed on another session case
+--
+-- Make sure to create cache
+SELECT * FROM t1;
+SELECT * FROM t1;
+ALTER DATABASE test2 RESET ALL;
+EOF
+ $PSQL -a test >> result 2>&1 <<EOF
+-- Make sure this does not access cache
+SELECT * FROM t1;
+EOF
+
+#echo '=== extended query test for "ALTER DATABASE is executed on another session" case ===' >> result
+# $PGPROTO -d test -f ../alter_database2.data |& del_details_from_error >> result
+# $PGPROTO -d test -f ../alter_database3.data |& del_details_from_error >> result
+
./shutdownall
cd ..
+
+ log=/tmp/diff
+ EXPECTED=expected.$mode
+ diff -c $EXPECTED testdir/result > $log
+ if [ $? != 0 ];then
+ echo "test failed in mode: $mode"
+ cat $log
+ rm $log
+ exit 1
+ fi
+ rm $log
done
exit 0
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2023 PgPool Global Development Group
+ * Copyright (c) 2003-2024 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
static bool temp_table_walker(Node *node, void *context);
static bool unlogged_table_walker(Node *node, void *context);
static bool view_walker(Node *node, void *context);
+static bool row_security_enabled(char *table_name);
+static bool row_security_enabled_walker(Node *node, void *context);
static bool is_temp_table(char *table_name);
static bool insertinto_or_locking_clause_walker(Node *node, void *context);
static bool is_immutable_function(char *fname);
return ctx.has_view;
}
+/*
+ * Return true if this SELECT has a row security enabled table.
+ */
+bool
+pool_has_row_security(Node *node)
+{
+
+ SelectContext ctx;
+
+ if (!IsA(node, SelectStmt))
+ return false;
+
+ ctx.row_security = false;
+
+ raw_expression_tree_walker(node, row_security_enabled_walker, &ctx);
+
+ return ctx.row_security;
+}
+
/*
* Return true if this SELECT has INSERT INTO or FOR SHARE or FOR UPDATE.
*/
return raw_expression_tree_walker(node, view_walker, context);
}
+/*
+ * Walker function to find a row security enabled table.
+ */
+static bool
+row_security_enabled_walker(Node *node, void *context)
+{
+ SelectContext *ctx = (SelectContext *) context;
+ char *relname;
+
+ if (node == NULL)
+ return false;
+
+ if (IsA(node, RangeVar))
+ {
+ RangeVar *rgv = (RangeVar *) node;
+
+ relname = make_table_name_from_rangevar(rgv);
+
+ ereport(DEBUG1,
+ (errmsg("row secuirty walker. checking relation \"%s\"", relname)));
+
+ if (row_security_enabled(relname))
+ {
+ ctx->row_security = true;
+ return false;
+ }
+ }
+ return raw_expression_tree_walker(node, row_security_enabled_walker, context);
+}
+
/*
* Determine whether table_name is a system catalog or not.
*/
return result;
}
+/*
+ * Returns true if table_name enables row security.
+ */
+static bool
+row_security_enabled(char *table_name)
+{
+/*
+ * Query to know if the target table enables row security. This is valid for
+ * PostgreSQL 9.5 or later. Remember that to_regclass() is available in
+ * PostgreSQL 9.4 or later and we can use to_regclass() unconditionally.
+ */
+#define ISROWSECURITYQUERY "SELECT count(*) FROM pg_catalog.pg_class AS c WHERE c.oid = pg_catalog.to_regclass('%s') AND c.relrowsecurity"
+
+ static POOL_RELCACHE * relcache;
+ POOL_CONNECTION_POOL *backend;
+ bool result;
+ char *query;
+
+ if (table_name == NULL)
+ return false;
+
+ backend = pool_get_session_context(false)->backend;
+
+ /*
+ * Check backend version. PostgreSQL 9.5 or later have relrowsecurity
+ * column.
+ */
+ if (Pgversion(backend)->major < 95)
+ return false;
+
+ query = ISROWSECURITYQUERY;
+
+ if (!relcache)
+ {
+ relcache = pool_create_relcache(pool_config->relcache_size, query,
+ int_register_func, int_unregister_func,
+ false);
+ if (relcache == NULL)
+ {
+ ereport(WARNING,
+ (errmsg("unable to create relcache, while checking for row security")));
+ return false;
+ }
+
+ }
+
+ /*
+ * Search relcache.
+ */
+ result = pool_search_relcache(relcache, backend, table_name) == 0 ? false : true;
+ return result;
+}
+
+
/*
* Judge if we have pgpool_regclass or not.
*/