diff --git a/src/common/backend/parser/parse_type.cpp b/src/common/backend/parser/parse_type.cpp index 52b8a9789..7ba70cbd0 100644 --- a/src/common/backend/parser/parse_type.cpp +++ b/src/common/backend/parser/parse_type.cpp @@ -1309,12 +1309,8 @@ HeapTuple FindPkgVariableType(ParseState* pstate, const TypeName* typname, int32 } /* handle var.col%TYPE firsr */ - tup = FindRowVarColType(typname->names); + tup = FindRowVarColType(typname->names, NULL, NULL, typmod_p); if (tup != NULL) { - typmod = typenameTypeMod(pstate, typname, (Type)tup); - if (typmod_p != NULL) { - *typmod_p = typmod; - } return tup; } diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index 97a80097e..c8e59385d 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -8546,11 +8546,12 @@ read_datatype(int tok) HeapTuple tup = NULL; int collectionType = PLPGSQL_COLLECTION_NONE; Oid tableOfIndexType = InvalidOid; - tup = FindRowVarColType(dtnames, &collectionType, &tableOfIndexType); + int32 typMod = -1; + tup = FindRowVarColType(dtnames, &collectionType, &tableOfIndexType, &typMod); if (tup != NULL) { Oid typOid = typeTypeId(tup); ReleaseSysCache(tup); - PLpgSQL_type* type = plpgsql_build_datatype(typOid, -1, InvalidOid); + PLpgSQL_type* type = plpgsql_build_datatype(typOid, typMod, InvalidOid); if (OidIsValid(tableOfIndexType)) { type->collectionType = collectionType; type->tableOfIndexType = tableOfIndexType; diff --git a/src/common/pl/plpgsql/src/pl_comp.cpp b/src/common/pl/plpgsql/src/pl_comp.cpp index e407d70eb..1bb5ce7eb 100644 --- a/src/common/pl/plpgsql/src/pl_comp.cpp +++ b/src/common/pl/plpgsql/src/pl_comp.cpp @@ -2050,7 +2050,7 @@ void getTableofTypeFromVar(PLpgSQL_var* var, int* collectionType, Oid* tableofIn } } -HeapTuple FindRowVarColType(List* nameList, int* collectionType, Oid* tableofIndexType) +HeapTuple FindRowVarColType(List* nameList, int* collectionType, Oid* tableofIndexType, int32* typMod) { if (u_sess->plsql_cxt.curr_compile_context == NULL) { return NULL; @@ -2110,10 +2110,16 @@ HeapTuple FindRowVarColType(List* nameList, int* collectionType, Oid* tableofInd if (datum->dtype == PLPGSQL_DTYPE_VAR) { /* scalar variable, just return the datatype */ typOid = ((PLpgSQL_var*)datum)->datatype->typoid; + if (typMod != NULL) { + *typMod = ((PLpgSQL_var*)datum)->datatype->atttypmod; + } getTableofTypeFromVar((PLpgSQL_var*)datum, collectionType, tableofIndexType); } else if (datum->dtype == PLPGSQL_DTYPE_ROW) { /* row variable, need to build a new one */ typOid = ((PLpgSQL_row*)datum)->rowtupdesc->tdtypeid; + if (typMod != NULL) { + *typMod = ((PLpgSQL_row*)datum)->rowtupdesc->tdtypmod; + } } break; } diff --git a/src/common/pl/plpgsql/src/pl_scanner.cpp b/src/common/pl/plpgsql/src/pl_scanner.cpp index 6a88c2d46..b4c4118c7 100644 --- a/src/common/pl/plpgsql/src/pl_scanner.cpp +++ b/src/common/pl/plpgsql/src/pl_scanner.cpp @@ -13,6 +13,7 @@ * * ------------------------------------------------------------------------- */ +#include "utils/builtins.h" #include "utils/plpgsql.h" #include "utils/pl_package.h" #include "catalog/pg_type.h" @@ -24,6 +25,7 @@ #define PG_KEYWORD(a, b, c) {a, b, c}, #define LENGTH_OF_DOT_AND_STR_END 4 +#define INT32_STRING_SIZE 12 /* * A word about keywords: * @@ -552,6 +554,9 @@ void plpgsql_append_object_typename(StringInfo buf, PLpgSQL_type *var_type) { errno_t ret; char* typcast = "::"; + char* left = "("; + char* right = ")"; + char* dot = ","; appendBinaryStringInfo(buf, typcast, 2); int len = strlen(var_type->typname) + strlen(var_type->typnamespace) + LENGTH_OF_DOT_AND_STR_END; @@ -565,6 +570,24 @@ void plpgsql_append_object_typename(StringInfo buf, PLpgSQL_type *var_type) ret = strcat_s(typname, len, "\""); securec_check(ret, "\0", "\0"); appendBinaryStringInfo(buf, typname, strlen(typname)); + if (var_type->atttypmod != -1) { + appendBinaryStringInfo(buf, left, 1); + if (var_type->typoid == NUMERICOID) { + int32 typmod = var_type->atttypmod - VARHDRSZ; + char* precision = (char*)palloc(INT32_STRING_SIZE); + char* scale = (char*)palloc(INT32_STRING_SIZE); + pg_ltoa((int32)(((uint32)(typmod) >> 16) & 0xffff), precision); + pg_ltoa((int32)(((uint32)typmod) & 0xffff), scale); + appendBinaryStringInfo(buf, precision, strlen(precision)); + appendBinaryStringInfo(buf, dot, 1); + appendBinaryStringInfo(buf, scale, strlen(scale)); + } else { + char* typMod = (char*)palloc(INT32_STRING_SIZE); + pg_ltoa(var_type->atttypmod, typMod); + appendBinaryStringInfo(buf, typMod, strlen(typMod)); + } + appendBinaryStringInfo(buf, right, 1); + } pfree_ext(typname); } diff --git a/src/include/utils/pl_package.h b/src/include/utils/pl_package.h index fe1065307..aef7ce828 100644 --- a/src/include/utils/pl_package.h +++ b/src/include/utils/pl_package.h @@ -71,5 +71,6 @@ extern List* GetPackageListName(const char* pkgName, const Oid nspOid); extern HeapTuple getPLpgsqlVarTypeTup(char* word); -extern HeapTuple FindRowVarColType(List* nameList, int* collectionType = NULL, Oid* tableofIndexType = NULL); +extern HeapTuple FindRowVarColType(List* nameList, int* collectionType = NULL, Oid* tableofIndexType = NULL, + int32* typMod = NULL); #endif diff --git a/src/test/regress/expected/package_typmod_test.out b/src/test/regress/expected/package_typmod_test.out new file mode 100644 index 000000000..bd50930f4 --- /dev/null +++ b/src/test/regress/expected/package_typmod_test.out @@ -0,0 +1,23 @@ +create type ty1 is (id int,cat1 bit(5)); +create or replace package pak1 as +var ty1; +type tp_tb1 is table of var.cat1%type; +tb1 tp_tb1; +procedure p1; +end pak1 ; +/ +create or replace package body pak1 as +procedure p1 as +begin +tb1=tp_tb1(12,13,5,0); +raise info '%', tb1; +end; +end pak1; +/ +call pak1.p1(); +INFO: {01100,01101,00101,00000} + p1 +---- + +(1 row) + diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index dac4e594e..e54fc5c60 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -716,7 +716,7 @@ test: plpgsql_assign_list test: plpgsql_package_type plpgsql_package_param test: plpgsql_record_attrname test: plpgsql_insert_record -test: hw_package_variable +test: hw_package_variable package_typmod_test test: autonomous_cursor test: plpgsql_reset_session #test: plancache limit rangefuncs prepare diff --git a/src/test/regress/sql/package_typmod_test.sql b/src/test/regress/sql/package_typmod_test.sql new file mode 100644 index 000000000..f355f8112 --- /dev/null +++ b/src/test/regress/sql/package_typmod_test.sql @@ -0,0 +1,17 @@ +create type ty1 is (id int,cat1 bit(5)); +create or replace package pak1 as +var ty1; +type tp_tb1 is table of var.cat1%type; +tb1 tp_tb1; +procedure p1; +end pak1 ; +/ +create or replace package body pak1 as +procedure p1 as +begin +tb1=tp_tb1(12,13,5,0); +raise info '%', tb1; +end; +end pak1; +/ +call pak1.p1(); \ No newline at end of file