diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index a8314649070d..b354b3a92f51 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -206,6 +206,7 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) GpExecIdentity exec_identity; bool shouldDispatch; bool needDtx; + List *toplevelOidCache = NIL; /* sanity checks: queryDesc must not be started already */ Assert(queryDesc != NULL); @@ -581,11 +582,16 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) * * For details please see github issue https://github.com/greenplum-db/gpdb/issues/10760 */ - List *toplevelOidCache = NIL; if (queryDesc->ddesc != NULL) { queryDesc->ddesc->sliceTable = estate->es_sliceTable; - toplevelOidCache = GetAssignedOidsForDispatch(); + /* + * For CTAS querys that contain initplan, we need to copy a new oid dispatch list, + * since the preprocess_initplan will start a subtransaction, and if it's rollbacked, + * the memory context of 'Oid dispatch context' will be reset, which will cause invalid + * list reference during the serialization of dispatch_oids when dispatching plan. + */ + toplevelOidCache = copyObject(GetAssignedOidsForDispatch()); } /* @@ -641,6 +647,12 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) estate->es_param_exec_vals, needDtx, true); } + + if (toplevelOidCache != NIL) + { + list_free(toplevelOidCache); + toplevelOidCache = NIL; + } } /* @@ -701,6 +713,11 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) } PG_CATCH(); { + if (toplevelOidCache != NIL) + { + list_free(toplevelOidCache); + toplevelOidCache = NIL; + } mppExecutorCleanup(queryDesc); PG_RE_THROW(); } diff --git a/src/test/regress/expected/gpctas.out b/src/test/regress/expected/gpctas.out index fe70c9664181..755a35b8daff 100644 --- a/src/test/regress/expected/gpctas.out +++ b/src/test/regress/expected/gpctas.out @@ -146,17 +146,16 @@ ALTER TABLE ctas_src DROP COLUMN col2; INSERT INTO ctas_src(col1, col3,col4,col5) SELECT g, 'a',True,g from generate_series(1,5) g; CREATE TABLE ctas_dst as SELECT col1,col3,col4,col5 FROM ctas_src order by 1; -NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'col4' as the Greenplum Database data distribution key for this table. -HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause. Creating a NULL policy entry. -- This will fail to find some of the rows, if they're distributed incorrectly. SELECT * FROM ctas_src, ctas_dst WHERE ctas_src.col1 = ctas_dst.col1; col1 | col3 | col4 | col5 | col1 | col3 | col4 | col5 ------+------+------+------+------+------+------+------ - 1 | a | t | 1 | 1 | a | t | 1 + 5 | a | t | 5 | 5 | a | t | 5 2 | a | t | 2 | 2 | a | t | 2 3 | a | t | 3 | 3 | a | t | 3 4 | a | t | 4 | 4 | a | t | 4 - 5 | a | t | 5 | 5 | a | t | 5 + 1 | a | t | 1 | 1 | a | t | 1 (5 rows) -- Github Issue 9365: https://github.com/greenplum-db/gpdb/issues/9365 @@ -203,8 +202,7 @@ CREATE TABLE ctas_base(a int, b int); NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table. HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. CREATE TABLE ctas_aocs WITH (appendonly=true, orientation=column) AS SELECT * FROM ctas_base WITH NO DATA; -NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'a' as the Greenplum Database data distribution key for this table. -HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause. Creating a NULL policy entry. SELECT * FROM ctas_aocs; a | b ---+--- @@ -303,3 +301,29 @@ from refresh materialized view sro_mv_issue_11999; ERROR: division by zero CONTEXT: SQL function "mv_action_select_issue_11999" statement 1 +-- Test CTAS + initplan, and an exception was raised in preprocess_initplans +CREATE OR REPLACE FUNCTION public.exception_func() + RETURNS refcursor + LANGUAGE plpgsql +AS $function$declare cname refcursor = 'result'; begin open cname for select 1; raise sqlstate '02000'; return cname; exception when sqlstate '02000' then return cname; end;$function$; +SELECT exception_func() INTO TEMPORARY test_tmp1; +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named '' as the Greenplum Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +SELECT * FROM test_tmp1; + exception_func +---------------- + result +(1 row) + +CREATE TEMPORARY TABLE test_tmp2 AS SELECT exception_func(); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named '' as the Greenplum Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +SELECT * FROM test_tmp2; + exception_func +---------------- + result +(1 row) + +DROP FUNCTION public.exception_func(); +DROP TABLE test_tmp1; +DROP TABLE test_tmp2; diff --git a/src/test/regress/sql/gpctas.sql b/src/test/regress/sql/gpctas.sql index 905f3fcf053d..01a47b1f3d15 100644 --- a/src/test/regress/sql/gpctas.sql +++ b/src/test/regress/sql/gpctas.sql @@ -199,3 +199,22 @@ from -- then refresh should error out refresh materialized view sro_mv_issue_11999; + + +-- Test CTAS + initplan, and an exception was raised in preprocess_initplans +CREATE OR REPLACE FUNCTION public.exception_func() + RETURNS refcursor + LANGUAGE plpgsql +AS $function$declare cname refcursor = 'result'; begin open cname for select 1; raise sqlstate '02000'; return cname; exception when sqlstate '02000' then return cname; end;$function$; + +SELECT exception_func() INTO TEMPORARY test_tmp1; + +SELECT * FROM test_tmp1; + +CREATE TEMPORARY TABLE test_tmp2 AS SELECT exception_func(); + +SELECT * FROM test_tmp2; + +DROP FUNCTION public.exception_func(); +DROP TABLE test_tmp1; +DROP TABLE test_tmp2;