From: Pavan Deolasee Date: Tue, 12 Sep 2017 06:47:19 +0000 (+0530) Subject: Ensure that database objects are created consistently. X-Git-Tag: XL_10_R1BETA1~124 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=f7d1d581c950191a465b8483173f2ad69ae8fffe;p=postgres-xl.git Ensure that database objects are created consistently. We now create views/materialised views on all nodes, unless they are temporary objects in which case they are created only on the local coordinator and the datanodes. Similarly, temporary sequences are created on the local coordinator and the datanodes. This solves many outstanding problems in the regression results where remote nodes used to fail because of non-existent type for a view or similar such issues. A few other test cases now started to work correctly and produce output matching upstream PG. So the expected output for those test cases has been appropriated fixed. Couple of sequences in the rangefuncs test case have been converted into permanent sequences because the subsequent SQL functions refer to them and hence fail if they do not exist on the remote coordinators. The problem with special RULE converting a regular table into a view goes away with the fix since DROP VIEW commands are now propgataed to the datanodes too. --- diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 0749400ccf..6dd3845153 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1231,8 +1231,8 @@ ProcessUtilityPost(PlannedStmt *pstmt, if (IS_PGXC_LOCAL_COORDINATOR) { ViewStmt *stmt = (ViewStmt *) parsetree; - if (stmt->view->relpersistence != RELPERSISTENCE_TEMP) - exec_type = EXEC_ON_COORDS; + is_temp = stmt->view->relpersistence == RELPERSISTENCE_TEMP; + exec_type = is_temp ? EXEC_ON_DATANODES : EXEC_ON_ALL_NODES; } break; @@ -1252,7 +1252,7 @@ ProcessUtilityPost(PlannedStmt *pstmt, /* In case this query is related to a SERIAL execution, just bypass */ if (!stmt->is_serial) is_temp = stmt->sequence->relpersistence == RELPERSISTENCE_TEMP; - exec_type = EXEC_ON_ALL_NODES; + exec_type = is_temp ? EXEC_ON_DATANODES : EXEC_ON_ALL_NODES; } break; @@ -1287,8 +1287,8 @@ ProcessUtilityPost(PlannedStmt *pstmt, * CREATE TABLE + SELECT INTO */ Assert(stmt->relkind == OBJECT_MATVIEW); - if (stmt->into->rel->relpersistence != RELPERSISTENCE_TEMP) - exec_type = EXEC_ON_COORDS; + is_temp = stmt->into->rel->relpersistence == RELPERSISTENCE_TEMP; + exec_type = is_temp ? EXEC_ON_DATANODES : EXEC_ON_ALL_NODES; } break; @@ -2578,9 +2578,14 @@ ProcessUtilitySlow(ParseState *pstate, break; case T_CreateTableAsStmt: - address = ExecCreateTableAs((CreateTableAsStmt *) parsetree, - queryString, params, queryEnv, - completionTag); + { + CreateTableAsStmt *stmt = (CreateTableAsStmt *) parsetree; + if (IS_PGXC_DATANODE && stmt->relkind == OBJECT_MATVIEW) + stmt->into->skipData = true; + address = ExecCreateTableAs((CreateTableAsStmt *) parsetree, + queryString, params, queryEnv, + completionTag); + } break; case T_RefreshMatViewStmt: @@ -4697,55 +4702,18 @@ ExecUtilityFindNodes(ObjectType object_type, { case OBJECT_SEQUENCE: *is_temp = IsTempTable(object_id); - exec_type = EXEC_ON_ALL_NODES; + if (*is_temp) + exec_type = EXEC_ON_DATANODES; + else + exec_type = EXEC_ON_ALL_NODES; break; case OBJECT_TABLE: - /* Do the check on relation kind */ - exec_type = ExecUtilityFindNodesRelkind(object_id, is_temp); - break; - - /* - * Views and rules, both permanent or temporary are created - * on Coordinators only. - */ case OBJECT_RULE: case OBJECT_VIEW: case OBJECT_MATVIEW: - /* Check if object is a temporary view */ - if ((*is_temp = IsTempTable(object_id))) - exec_type = EXEC_ON_NONE; - else - exec_type = EXEC_ON_COORDS; - break; - case OBJECT_INDEX: - /* Check if given index uses temporary tables */ - { - Relation rel; - bool is_matview; - - rel = relation_open(object_id, NoLock); - - *is_temp = (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP); - is_matview = (rel->rd_rel->relkind == RELKIND_MATVIEW); - - relation_close(rel, NoLock); - - exec_type = EXEC_ON_NONE; - if (*is_temp) - { - if (!is_matview) - exec_type = EXEC_ON_DATANODES; - } - else - { - if (!is_matview) - exec_type = EXEC_ON_ALL_NODES; - else - exec_type = EXEC_ON_COORDS; - } - } + exec_type = ExecUtilityFindNodesRelkind(object_id, is_temp); break; default: @@ -4771,7 +4739,6 @@ ExecUtilityFindNodesRelkind(Oid relid, bool *is_temp) switch (relkind_str) { - case RELKIND_SEQUENCE: case RELKIND_RELATION: case RELKIND_PARTITIONED_TABLE: if ((*is_temp = IsTempTable(relid))) @@ -4798,7 +4765,7 @@ ExecUtilityFindNodesRelkind(Oid relid, bool *is_temp) /* Release system cache BEFORE looking at the parent table */ ReleaseSysCache(tuple); - return ExecUtilityFindNodesRelkind(table_relid, is_temp); + exec_type = ExecUtilityFindNodesRelkind(table_relid, is_temp); } else { @@ -4809,18 +4776,13 @@ ExecUtilityFindNodesRelkind(Oid relid, bool *is_temp) break; case RELKIND_VIEW: - if ((*is_temp = IsTempTable(relid))) - exec_type = EXEC_ON_NONE; - else - exec_type = EXEC_ON_COORDS; - break; - + case RELKIND_SEQUENCE: case RELKIND_MATVIEW: /* Check if object is a temporary view */ if ((*is_temp = IsTempTable(relid))) - exec_type = EXEC_ON_NONE; + exec_type = EXEC_ON_DATANODES; else - exec_type = EXEC_ON_COORDS; + exec_type = EXEC_ON_ALL_NODES; break; default: diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index 6a6492f3fb..2a40b072ab 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -1275,9 +1275,7 @@ CREATE VIEW rec1v AS SELECT * FROM rec1; CREATE VIEW rec2v AS SELECT * FROM rec2; SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2v WHERE b = y)); -ERROR: relation "rec2v" does not exist ALTER POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1v WHERE y = b)); -ERROR: relation "rec1v" does not exist SET SESSION AUTHORIZATION regress_rls_bob; SELECT * FROM rec1; -- fail, mutual recursion via views ERROR: infinite recursion detected in policy for relation "rec1" @@ -1287,14 +1285,13 @@ ERROR: infinite recursion detected in policy for relation "rec1" SET SESSION AUTHORIZATION regress_rls_bob; \set VERBOSITY terse \\ -- suppress cascade details DROP VIEW rec1v, rec2v CASCADE; +NOTICE: drop cascades to 2 other objects \set VERBOSITY default CREATE VIEW rec1v WITH (security_barrier) AS SELECT * FROM rec1; CREATE VIEW rec2v WITH (security_barrier) AS SELECT * FROM rec2; SET SESSION AUTHORIZATION regress_rls_alice; CREATE POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2v WHERE b = y)); -ERROR: policy "r1" for table "rec1" already exists CREATE POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1v WHERE y = b)); -ERROR: policy "r2" for table "rec2" already exists SET SESSION AUTHORIZATION regress_rls_bob; SELECT * FROM rec1; -- fail, mutual recursion via s.b. views ERROR: infinite recursion detected in policy for relation "rec1" @@ -1343,13 +1340,12 @@ EXPLAIN (COSTS OFF) SELECT * FROM only s1 WHERE f_leak(b); SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p1 ON s1 USING (a in (select x from v2)); -- using VIEW in RLS policy -ERROR: relation "v2" does not exist SET SESSION AUTHORIZATION regress_rls_bob; SELECT * FROM s1 WHERE f_leak(b); -- OK - a | b ----+---------------------------------- - 2 | c81e728d9d4c2f636f067f89cc14862c - 4 | a87ff679a2f3e71d9181a67b7542122c + a | b +----+---------------------------------- + -4 | 0267aaf632e87a63288a08331f22c7c3 + 6 | 1679091c5a880faf6fb5e6087eb1b2dc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM s1 WHERE f_leak(b); @@ -1361,7 +1357,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM s1 WHERE f_leak(b); SubPlan 1 -> Remote Subquery Scan on all (datanode_1,datanode_2) -> Seq Scan on s2 - Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text)) + Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) (7 rows) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; @@ -1387,7 +1383,7 @@ EXPLAIN (COSTS OFF) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like SubPlan 1 -> Remote Subquery Scan on all (datanode_1,datanode_2) -> Seq Scan on s2 s2_1 - Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text)) + Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) (13 rows) SET SESSION AUTHORIZATION regress_rls_alice; diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index 635039fac9..86df2bcc2d 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -525,9 +525,25 @@ select row_to_json(i) from int8_tbl i(x,y); create temp view vv1 as select * from int8_tbl; select row_to_json(i) from vv1 i; -ERROR: cache lookup failed for type 0 + row_to_json +------------------------------------------------ + {"q1":123,"q2":456} + {"q1":123,"q2":4567890123456789} + {"q1":4567890123456789,"q2":123} + {"q1":4567890123456789,"q2":4567890123456789} + {"q1":4567890123456789,"q2":-4567890123456789} +(5 rows) + select row_to_json(i) from vv1 i(x,y); -ERROR: cache lookup failed for type 0 + row_to_json +---------------------------------------------- + {"x":123,"y":456} + {"x":123,"y":4567890123456789} + {"x":4567890123456789,"y":123} + {"x":4567890123456789,"y":4567890123456789} + {"x":4567890123456789,"y":-4567890123456789} +(5 rows) + select row_to_json(ss) from (select q1, q2 from int8_tbl) as ss; row_to_json diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index c355f10c4c..a5d78d029d 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -650,13 +650,29 @@ create temp table table_a(id integer); insert into table_a values (42); create temp view view_a as select * from table_a; select view_a from view_a; -ERROR: cache lookup failed for type 0 + view_a +-------- + (42) +(1 row) + select (select view_a) from view_a; -ERROR: cache lookup failed for type 0 + view_a +-------- + (42) +(1 row) + select (select (select view_a)) from view_a; -ERROR: cache lookup failed for type 0 + view_a +-------- + (42) +(1 row) + select (select (a.*)::text) from view_a a; -ERROR: cache lookup failed for type 0 + a +------ + (42) +(1 row) + -- -- Check that whole-row Vars reading the result of a subselect don't include -- any junk columns therein diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index 647d8cf3f7..b9a54376ac 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -911,32 +911,38 @@ INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i); CREATE VIEW rw_view1 AS SELECT b AS bb, a AS aa FROM base_tbl; CREATE FUNCTION rw_view1_aa(x rw_view1) RETURNS int AS $$ SELECT x.aa $$ LANGUAGE sql; -ERROR: type rw_view1 does not exist UPDATE rw_view1 v SET bb='Updated row 2' WHERE rw_view1_aa(v)=2 RETURNING rw_view1_aa(v), v.bb; -ERROR: function rw_view1_aa(rw_view1) does not exist -LINE 1: UPDATE rw_view1 v SET bb='Updated row 2' WHERE rw_view1_aa(v... - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. + rw_view1_aa | bb +-------------+--------------- + 2 | Updated row 2 +(1 row) + SELECT * FROM base_tbl; - a | b -----+-------- + a | b +----+--------------- -2 | Row -2 -1 | Row -1 0 | Row 0 1 | Row 1 - 2 | Row 2 + 2 | Updated row 2 (5 rows) EXPLAIN (costs off, nodes off) UPDATE rw_view1 v SET bb='Updated row 2' WHERE rw_view1_aa(v)=2 RETURNING rw_view1_aa(v), v.bb; -ERROR: function rw_view1_aa(rw_view1) does not exist -LINE 2: UPDATE rw_view1 v SET bb='Updated row 2' WHERE rw_view1_aa(v... - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. + QUERY PLAN +-------------------------------------------------------- + Remote Subquery Scan on any + -> Update on base_tbl + -> Index Scan using base_tbl_pkey on base_tbl + Index Cond: (a = 2) +(4 rows) + DROP TABLE base_tbl CASCADE; -NOTICE: drop cascades to view rw_view1 +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to view rw_view1 +drop cascades to function rw_view1_aa(rw_view1) -- permissions checks CREATE USER regress_view_user1; CREATE USER regress_view_user2; diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql index e309f4f838..4e30a02fa0 100644 --- a/src/test/regress/sql/rangefuncs.sql +++ b/src/test/regress/sql/rangefuncs.sql @@ -228,8 +228,8 @@ DROP TABLE foo2; DROP TABLE foo; -- Rescan tests -- -CREATE TEMPORARY SEQUENCE foo_rescan_seq1; -CREATE TEMPORARY SEQUENCE foo_rescan_seq2; +CREATE SEQUENCE foo_rescan_seq1; +CREATE SEQUENCE foo_rescan_seq2; CREATE TYPE foo_rescan_t AS (i integer, s bigint); CREATE FUNCTION foo_sql(int,int) RETURNS setof foo_rescan_t AS 'SELECT i, nextval(''foo_rescan_seq1'') FROM generate_series($1,$2) i;' LANGUAGE SQL;