diff --git a/src/common/pl/plpgsql/src/pl_exec.cpp b/src/common/pl/plpgsql/src/pl_exec.cpp index b83a94e19..760249068 100644 --- a/src/common/pl/plpgsql/src/pl_exec.cpp +++ b/src/common/pl/plpgsql/src/pl_exec.cpp @@ -10018,30 +10018,58 @@ void exec_assign_value(PLpgSQL_execstate* estate, PLpgSQL_datum* target, Datum v * Evaluate the subscripts, switch into left-to-right order. * Like ExecEvalArrayRef(), complain if any subscript is null. */ - for (i = 0; i < nsubscripts; i++) { - bool subisnull = false; + bool isNestedArray = ((PLpgSQL_var*)target)->nest_table != NULL; - subscriptvals[i] = exec_eval_integer(estate, subscripts[nsubscripts - 1 - i], &subisnull); - if (subisnull) { + if (isNestedArray) { + Oid subscriptType = ((PLpgSQL_var*)target)->datatype->tableOfIndexType; + HTAB* elemTableOfIndex = ((PLpgSQL_var*)target)->tableOfIndex; + PLpgSQL_var* innerVar = evalSubsciptsNested(estate, (PLpgSQL_var*)target, subscripts, nsubscripts, + 0, subscriptvals, subscriptType, elemTableOfIndex); + target = (PLpgSQL_datum*)innerVar; + /* should assign inner var as an array, copy value's index */ + if (innerVar->ispkg) { + MemoryContext temp = MemoryContextSwitchTo(innerVar->pkg->pkg_cxt); + innerVar->tableOfIndex = copyTableOfIndex(tableOfIndex); + MemoryContextSwitchTo(temp); + } else { + innerVar->tableOfIndex = copyTableOfIndex(tableOfIndex); + } + if (tableOfIndexInfo != NULL && innerVar->nest_layers != tableOfIndexInfo->tableOfLayers) { ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmodule(MOD_PLSQL), - errmsg("array subscript in assignment must not be null"))); + errmsg("Nest layer of assigned value is miss match to tableof var(%s)'s expection", + innerVar->refname))); } - /* - * Clean up in case the subscript expression wasn't - * simple. We can't do exec_eval_cleanup, but we can do - * this much (which is safe because the integer subscript - * value is surely pass-by-value), and we must do it in - * case the next subscript expression isn't simple either. - */ - if (estate->eval_tuptable != NULL) { - SPI_freetuptable(estate->eval_tuptable); + exec_assign_value(estate, target, PointerGetDatum(value), + valtype, isNull, innerVar->tableOfIndex); + break; + } else { + for (i = 0; i < nsubscripts; i++) { + bool subisnull = false; + + subscriptvals[i] = exec_eval_integer(estate, subscripts[nsubscripts - 1 - i], &subisnull); + if (subisnull) { + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmodule(MOD_PLSQL), + errmsg("array subscript in assignment must not be null"))); + } + + /* + * Clean up in case the subscript expression wasn't + * simple. We can't do exec_eval_cleanup, but we can do + * this much (which is safe because the integer subscript + * value is surely pass-by-value), and we must do it in + * case the next subscript expression isn't simple either. + */ + if (estate->eval_tuptable != NULL) { + SPI_freetuptable(estate->eval_tuptable); + } + estate->eval_tuptable = NULL; } - estate->eval_tuptable = NULL; } - /* Now we can restore caller's SPI_execute result if any. */ AssertEreport(estate->eval_tuptable == NULL, MOD_PLSQL, "eval tuptable should not be null"); estate->eval_tuptable = save_eval_tuptable; diff --git a/src/test/regress/expected/plpgsql_nested_array_and_record.out b/src/test/regress/expected/plpgsql_nested_array_and_record.out index 85e5d8191..53c40b5ba 100644 --- a/src/test/regress/expected/plpgsql_nested_array_and_record.out +++ b/src/test/regress/expected/plpgsql_nested_array_and_record.out @@ -26,6 +26,36 @@ NOTICE: RESULT: 2 NOTICE: RESULT: 3 NOTICE: RESULT: 4 NOTICE: RESULT: 5 +CREATE OR REPLACE PROCEDURE test_nested_array as +TYPE typ_PLArray_case0001 IS varray(3) OF integer; +TYPE typ_PLArray_case0002 IS varray(3) OF typ_PLArray_case0001; +nstarr typ_PLArray_case0002; +BEGIN + nstarr(1):=1; + RAISE NOTICE '二维数组(1):%', nstarr(1); +END; +/ +CALL test_nested_array(); +ERROR: array value must start with "{" or dimension information +CONTEXT: PL/pgSQL function test_nested_array() line 5 at assignment +CREATE OR REPLACE PROCEDURE test_nested_array as +TYPE typ_PLArray_case0001 IS varray(3) OF integer; +TYPE typ_PLArray_case0002 IS varray(3) OF typ_PLArray_case0001; +nstarr typ_PLArray_case0002; +arr typ_PLArray_case0001; +BEGIN + arr(1):=1; + nstarr(1):=arr; + RAISE NOTICE '二维数组(1):%', nstarr(1); +END; +/ +CALL test_nested_array(); +NOTICE: 二维数组(1):{1} + test_nested_array +------------------- + +(1 row) + -- record of arrays DECLARE TYPE arr1 IS VARRAY(5) OF INTEGER; @@ -149,4 +179,6 @@ NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to function plpgsql_nested_array_and_record.p_plarray_1() drop cascades to function plpgsql_nested_array_and_record.p_plarray_2(undefined) DROP SCHEMA plpgsql_nested_array_and_record CASCADE; -NOTICE: drop cascades to function test_nested() +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function test_nested_array() +drop cascades to function test_nested() diff --git a/src/test/regress/sql/plpgsql_nested_array_and_record.sql b/src/test/regress/sql/plpgsql_nested_array_and_record.sql index 066fe5e9a..be31c8b8a 100644 --- a/src/test/regress/sql/plpgsql_nested_array_and_record.sql +++ b/src/test/regress/sql/plpgsql_nested_array_and_record.sql @@ -18,6 +18,30 @@ BEGIN END; / +CREATE OR REPLACE PROCEDURE test_nested_array as +TYPE typ_PLArray_case0001 IS varray(3) OF integer; +TYPE typ_PLArray_case0002 IS varray(3) OF typ_PLArray_case0001; +nstarr typ_PLArray_case0002; +BEGIN + nstarr(1):=1; + RAISE NOTICE '二维数组(1):%', nstarr(1); +END; +/ +CALL test_nested_array(); + +CREATE OR REPLACE PROCEDURE test_nested_array as +TYPE typ_PLArray_case0001 IS varray(3) OF integer; +TYPE typ_PLArray_case0002 IS varray(3) OF typ_PLArray_case0001; +nstarr typ_PLArray_case0002; +arr typ_PLArray_case0001; +BEGIN + arr(1):=1; + nstarr(1):=arr; + RAISE NOTICE '二维数组(1):%', nstarr(1); +END; +/ +CALL test_nested_array(); + -- record of arrays DECLARE TYPE arr1 IS VARRAY(5) OF INTEGER;