!4371 修复函数体存在类型依赖,调用函数时自动重编译失效的问题

Merge pull request !4371 from lukeman/master
This commit is contained in:
opengauss_bot
2023-11-06 07:10:18 +00:00
committed by Gitee
12 changed files with 262 additions and 67 deletions

View File

@ -548,7 +548,7 @@ bool SetPgObjectValid(Oid oid, PgObjectType objectType, bool valid)
values[Anum_pg_object_valid -1] = BoolGetDatum(valid);
replaces[Anum_pg_object_valid -1] = true;
HeapTuple new_tuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
(void)simple_heap_update(relation, &new_tuple->t_self, new_tuple, true);//debug tuple->t_self
(void)simple_heap_update(relation, &new_tuple->t_self, new_tuple, true);
CatalogUpdateIndexes(relation, new_tuple);
heap_freetuple(new_tuple);
ReleaseSysCache(tuple);

View File

@ -16615,12 +16615,11 @@ param_name: type_function_name
;
func_return:
func_type {
if (enable_plpgsql_gsdependency_guc()) {
pg_yyget_extra(yyscanner)->core_yy_extra.return_pos_end = yylloc;
}
}
func_type
{
if (enable_plpgsql_gsdependency_guc()) {
pg_yyget_extra(yyscanner)->core_yy_extra.return_pos_end = yylloc;
}
/* We can catch over-specified results here if we want to,
* but for now better to silently swallow typmod, etc.
* - thomas 2000-03-22

View File

@ -562,6 +562,9 @@ bool gsplsql_set_pkg_func_status(Oid schema_oid, Oid pkg_oid, bool status)
foreach(cell, list) {
Oid func_oid = lfirst_oid(cell);
result = SetPgObjectValid(func_oid, OBJECT_TYPE_PROC, status) || result;
if (!status) {
CacheInvalidateFunction(func_oid, pkg_oid);
}
}
list_free(list);
return result;
@ -1118,7 +1121,9 @@ static inline bool gsplsql_invalidate_func(Oid func_oid, Oid curr_compile_oid)
if (!OidIsValid(func_oid) || func_oid == curr_compile_oid) {
return false;
}
return SetPgObjectValid(func_oid, OBJECT_TYPE_PROC, false);
bool result = SetPgObjectValid(func_oid, OBJECT_TYPE_PROC, false);
CacheInvalidateFunction(func_oid, InvalidOid);
return result;
}
static bool gsplsql_invalidate_pkg(const char *schemaName, const char *pkgName, bool isSpec, Oid currCompileOid)

View File

@ -1447,6 +1447,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no
plpgsql_build_varrayType($2->name, $2->lineno, $9, true);
if (IS_PACKAGE) {
plpgsql_build_package_array_type($2->name, $9->typoid, TYPCATEGORY_ARRAY, $9->dependExtend);
} else if (enable_plpgsql_gsdependency()) {
gsplsql_build_gs_type_in_body_dependency($9);
}
pfree_ext($2->name);
pfree($2);
@ -1482,6 +1484,12 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no
plpgsql_build_varrayType($2->name, $2->lineno, newp, true);
if (IS_PACKAGE) {
plpgsql_build_package_array_type($2->name, newp->typoid, TYPCATEGORY_ARRAY);
} else if (enable_plpgsql_gsdependency()) {
PLpgSQL_rec_type* rec_var = (PLpgSQL_rec_type*)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$9];
int i;
for (i = 0; i < rec_var->attrnum; i++) {
gsplsql_build_gs_type_in_body_dependency(rec_var->types[i]);
}
}
pfree_ext($2->name);
pfree($2);
@ -1601,6 +1609,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no
plpgsql_build_tableType($2->name, $2->lineno, $6, true);
if (IS_PACKAGE) {
plpgsql_build_package_array_type($2->name, $6->typoid, TYPCATEGORY_TABLEOF, $6->dependExtend);
} else if (enable_plpgsql_gsdependency()) {
gsplsql_build_gs_type_in_body_dependency($6);
}
pfree_ext($2->name);
pfree($2);
@ -1663,6 +1673,12 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no
plpgsql_build_tableType($2->name, $2->lineno, newp, true);
if (IS_PACKAGE) {
plpgsql_build_package_array_type($2->name, newp->typoid, TYPCATEGORY_TABLEOF);
} else if (enable_plpgsql_gsdependency()) {
PLpgSQL_rec_type* rec_var = (PLpgSQL_rec_type*)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$6];
int i;
for (i = 0; i < rec_var->attrnum; i++) {
gsplsql_build_gs_type_in_body_dependency(rec_var->types[i]);
}
}
pfree_ext($2->name);
pfree($2);
@ -1775,6 +1791,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no
} else {
plpgsql_build_package_array_type($2->name, $6->typoid, TYPCATEGORY_TABLEOF_INTEGER, $6->dependExtend);
}
} else if (enable_plpgsql_gsdependency()) {
gsplsql_build_gs_type_in_body_dependency($6);
}
pfree_ext($2->name);
pfree($2);
@ -1858,6 +1876,12 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no
} else {
plpgsql_build_package_array_type($2->name, newp->typoid, TYPCATEGORY_TABLEOF_INTEGER);
}
} else if (enable_plpgsql_gsdependency()) {
int i;
PLpgSQL_rec_type* rec_var = (PLpgSQL_rec_type*)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$6];
for (i = 0; i < rec_var->attrnum; i++) {
gsplsql_build_gs_type_in_body_dependency(rec_var->types[i]);
}
}
pfree_ext($2->name);
pfree($2);
@ -12704,24 +12728,12 @@ static void plpgsql_build_package_array_type(const char* typname,Oid elemtypoid
Oid oldtypeoid = GetSysCacheOid2(TYPENAMENSP, PointerGetDatum(casttypename),
ObjectIdGetDatum(pkgNamespaceOid));
bool oldtypeoidIsValid = OidIsValid(oldtypeoid);
if (enable_plpgsql_gsdependency() && u_sess->plsql_cxt.need_create_depend) {
char* schemaName = get_namespace_name(pkgNamespaceOid);
char* packageName = GetPackageName(pkgOid);
bool dependUndef = gsplsql_check_type_depend_undefined(schemaName, packageName, typname);
pfree_ext(schemaName);
pfree_ext(packageName);
if (dependUndef) {
ObjectAddress address;
address.classId = TypeRelationId;
address.objectId = oldtypeoid;
address.objectSubId = 0;
performDeletion(&address, DROP_CASCADE, PERFORM_DELETION_INTERNAL);
oldtypeoidIsValid = false;
}
}
if (OidIsValid(oldtypeoid)) {
/* alread build one, just return */
if(IsPackageDependType(oldtypeoid, u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile_package->pkg_oid)) {
if(IsPackageDependType(oldtypeoid, pkgOid)) {
if (CompileWhich() == PLPGSQL_COMPILE_PACKAGE) {
(void)gsplsql_flush_undef_ref_type_dependency(oldtypeoid);
}
return;
} else {
ereport(errstate,
@ -12791,6 +12803,9 @@ static void plpgsql_build_package_array_type(const char* typname,Oid elemtypoid
myself.objectSubId = 0;
recordDependencyOn(&referenced, &myself, DEPENDENCY_AUTO);
CommandCounterIncrement();
if (CompileWhich() == PLPGSQL_COMPILE_PACKAGE && typtyp != TYPTYPE_TABLEOF) {
(void)gsplsql_build_ref_type_dependency(referenced.objectId);
}
pfree_ext(casttypename);
}

View File

@ -1276,7 +1276,7 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
FlushErrorState();
}
PG_END_TRY();
}else {
} else {
bool save_isPerform = u_sess->parser_cxt.isPerform;
u_sess->parser_cxt.isPerform = false;
parse_rc = plpgsql_yyparse();

View File

@ -725,6 +725,20 @@ Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
has_switch = true;
}
bool save_need_create_depend = u_sess->plsql_cxt.need_create_depend;
u_sess->plsql_cxt.need_create_depend = false;
_PG_init();
/*
* Connect to SPI manager
*/
SPI_STACK_LOG("connect", NULL, NULL);
rc = SPI_connect_ext(DestSPI, NULL, NULL, nonatomic ? SPI_OPT_NONATOMIC : 0, func_oid);
if (rc != SPI_OK_CONNECT) {
ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("SPI_connect failed: %s when execute PLSQL function.", SPI_result_code_string(rc))));
}
Oid package_oid = get_package_id(func_oid);
if (OidIsValid(package_oid)) {
if (u_sess->plsql_cxt.curr_compile_context == NULL ||
@ -742,19 +756,7 @@ Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
}
}
}
int fun_arg = fcinfo->nargs;
_PG_init();
/*
* Connect to SPI manager
*/
SPI_STACK_LOG("connect", NULL, NULL);
rc = SPI_connect_ext(DestSPI, NULL, NULL, nonatomic ? SPI_OPT_NONATOMIC : 0, func_oid);
if (rc != SPI_OK_CONNECT) {
ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("SPI_connect failed: %s when execute PLSQL function.", SPI_result_code_string(rc))));
}
#ifdef ENABLE_MULTIPLE_NODES
bool outer_is_stream = false;
bool outer_is_stream_support = false;
@ -773,7 +775,6 @@ Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
#endif
int connect = SPI_connectid();
Oid firstLevelPkgOid = InvalidOid;
bool save_need_create_depend = u_sess->plsql_cxt.need_create_depend;
bool save_curr_status = GetCurrCompilePgObjStatus();
PG_TRY();
{
@ -787,31 +788,15 @@ Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
if (func == NULL) {
u_sess->plsql_cxt.compile_has_warning_info = false;
SetCurrCompilePgObjStatus(true);
if (enable_plpgsql_gsdependency_guc()) {
if (gsplsql_is_undefined_func(func_oid)) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION),
(errmsg("\"%s\" header is undefined, you can try to recreate", get_func_name(func_oid)))));
}
if (GetPgObjectValid(func_oid, OBJECT_TYPE_PROC)) {
u_sess->plsql_cxt.need_create_depend = false;
} else {
u_sess->plsql_cxt.need_create_depend = true;
}
}
func = plpgsql_compile(fcinfo, false);
if (func == NULL) {
ereport(ERROR, (errcode(ERRCODE_NO_FUNCTION_PROVIDED), errmodule(MOD_PLSQL),
errmsg("compile function error."),
errdetail("It may be because the compilation encountered an error and the exception was caught."),
errcause("compile procedure error."),
erraction("compile function result is null, it has error")));
}
if (enable_plpgsql_gsdependency_guc()) {
if (!OidIsValid(func->pkg_oid)) {
SetPgObjectValid(func_oid, OBJECT_TYPE_PROC, true);
if (enable_plpgsql_gsdependency_guc() && func != NULL) {
SetPgObjectValid(func_oid, OBJECT_TYPE_PROC, GetCurrCompilePgObjStatus());
if (!GetCurrCompilePgObjStatus()) {
ereport(WARNING, (errmodule(MOD_PLSQL),
errmsg("Function %s recompile with compilation errors, please use ALTER COMPILE to recompile.",
get_func_name(func_oid))));
}
}
u_sess->plsql_cxt.need_create_depend = save_need_create_depend;
}
if (func->fn_readonly) {
stp_disable_xact_and_set_err_msg(&savedisAllowCommitRollback, STP_XACT_IMMUTABLE);
@ -1026,11 +1011,11 @@ Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
/* destory all the SPI connect created in this PL function. */
SPI_disconnect(connect);
u_sess->plsql_cxt.need_create_depend = save_need_create_depend;
/* re-throw the original error messages */
ReThrowError(edata);
}
PG_END_TRY();
u_sess->plsql_cxt.need_create_depend = save_need_create_depend;
/* clean stp save pointer if the outermost function is end. */
if (u_sess->SPI_cxt._connected == 0) {
t_thrd.utils_cxt.STPSavedResourceOwner = NULL;

View File

@ -2390,7 +2390,7 @@ static void RecompileFunctionWithArgs(CompileStmt* stmt)
if (PROC_IS_PRO(get_func_prokind(func_oid)) && stmt->compileItem == COMPILE_FUNCTION) {
ReportRecompileFuncWarning(stmt);
}
if (!IsNeedRecompile(func_oid)) {
if (IsNeedRecompile(func_oid)) {
RecompileSingleFunction(func_oid, stmt->compileItem == COMPILE_PROCEDURE);
return;
}

View File

@ -273,6 +273,7 @@ static void RecompileSinglePackage(Oid package_oid, bool is_spec)
u_sess->plsql_cxt.curr_compile_context = save_compile_context;
u_sess->plsql_cxt.compile_status = save_compile_status;
u_sess->plsql_cxt.need_create_depend = save_need_create_depend;
u_sess->plsql_cxt.during_compile = false;
clearCompileContextList(save_compile_list_length);
u_sess->plsql_cxt.running_pkg_oid = InvalidOid;
clear_plsql_ctx_line_info();

View File

@ -143,5 +143,4 @@ extern void gsplsql_delete_unrefer_depend_obj_oid(Oid ref_obj_oid, bool skip_in_
extern bool gsplsql_check_type_depend_ast_equal(Relation obj_rel, Oid obj_oid, const char* equal_ast);
extern bool gsplsql_search_depend_obj_by_oid(Oid oid, GsDependObjDesc* obj_desc);
extern void gsplsql_remove_type_gs_dependency(const GsDependObjDesc* obj_desc);
#endif /* GS_DEPENDENCIES_FN_H */

View File

@ -2651,7 +2651,7 @@ select a.schemaname as sn, a.packagename as pn, a.objectname as on, a.refobjpos
order by a.schemaname, a.objectname, a.refobjpos, b.type, b.name;
sn | pn | on | refpos | refsn | refpn | refon | refot | refast
---------------------+------+-------------------------------------+--------+---------------------+-------+-------------------------------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------
plpgsql_depend_type | null | proc1(plpgsql_depend_type.pkg.arr1) | 4 | plpgsql_depend_type | pkg | arr1 | 3 | {DependenciesUndefined}
plpgsql_depend_type | null | proc1(plpgsql_depend_type.pkg.arr1) | 4 | plpgsql_depend_type | pkg | arr1 | 3 | {DependenciesType :typType b :typCategory A :attrInfo <> :isRel false :elemTypName plpgsql_depend_type.sr :idxByTypName <>}
| | | | plpgsql_depend_type | null | proc1(plpgsql_depend_type.pkg.arr1) | 5 | {DependenciesProchead :undefined false :proName proc1 :proArgSrc v_1\ pkg.arr1 :funcHeadSrc create\ or\ replace\ procedure\ proc1\(v_1\ pkg.arr1\)}
(2 rows)

View File

@ -268,13 +268,133 @@ QUERY: DECLARE begin
select into v1 values (1,ROW(1,'zhang','M',1));
RAISE INFO 'call p_in: %', p_in;
end
-- select oid,* from pg_type where typname='stu';
-- test 3
create procedure test_subtype_proc is
xx s_type;
begin
xx := (1,'aaa','bbb');
raise notice '%',xx;
end;
/
call test_subtype_proc();
NOTICE: (1,aaa,bbb)
test_subtype_proc
-------------------
(1 row)
alter type s_type ADD attribute a int;
--修改后,预期调用成功
call test_subtype_proc();
NOTICE: (1,aaa,bbb,)
test_subtype_proc
-------------------
(1 row)
--手动触发编译, 调用成功
alter procedure test_subtype_proc compile;
call test_subtype_proc();
NOTICE: (1,aaa,bbb,)
test_subtype_proc
-------------------
(1 row)
-- test 4
create or replace package pkg
is
procedure proc1();
end pkg;
/
create or replace package body pkg
is
xxx s_type;
procedure proc1() as
yyy s_type;
begin
xxx:= (1,'aaa','aaaaa');
yyy:= (2,'bbb','bbbbb');
RAISE INFO 'call xxx: %, yyy: %', xxx, yyy;
end;
end pkg;
/
call pkg.proc1();
INFO: call xxx: (1,aaa,aaaaa,), yyy: (2,bbb,bbbbb,)
proc1
-------
(1 row)
alter type s_type ADD attribute b int;
--修改后,预期调用成功
call pkg.proc1();
INFO: call xxx: (1,aaa,aaaaa,,), yyy: (2,bbb,bbbbb,,)
proc1
-------
(1 row)
--手动触发编译, 调用成功
alter package pkg compile;
call pkg.proc1();
INFO: call xxx: (1,aaa,aaaaa,,), yyy: (2,bbb,bbbbb,,)
proc1
-------
(1 row)
-- test 5
create or replace package pkg
is
procedure proc1(p_in s_type);
end pkg;
/
create or replace package body pkg
is
xxx s_type;
procedure proc1(p_in s_type) as
yyy s_type;
begin
xxx:= (1,'aaa','aaaaa');
yyy:= (2,'bbb','bbbbb');
RAISE INFO 'call xxx: %, yyy: %, p_in: %', xxx, yyy, p_in;
end;
end pkg;
/
call pkg.proc1((1,'zhang','M',1,2));
INFO: call xxx: (1,aaa,aaaaa,,), yyy: (2,bbb,bbbbb,,), p_in: (1,zhang,M,1,2)
proc1
-------
(1 row)
alter type s_type ADD attribute c int;
--修改后,预期调用成功
call pkg.proc1((1,'zhang','M',1,2,3));
INFO: call xxx: (1,aaa,aaaaa,,,), yyy: (2,bbb,bbbbb,,,), p_in: (1,zhang,M,1,2,3)
proc1
-------
(1 row)
--手动触发编译, 调用成功
alter package pkg compile;
call pkg.proc1((1,'zhang','M',1,2,3));
INFO: call xxx: (1,aaa,aaaaa,,,), yyy: (2,bbb,bbbbb,,,), p_in: (1,zhang,M,1,2,3)
proc1
-------
(1 row)
-- clean
drop schema plpgsql_recompile cascade;
NOTICE: drop cascades to 6 other objects
NOTICE: drop cascades to 7 other objects
DETAIL: drop cascades to type s_type
drop cascades to function type_alter(s_type)
drop cascades to table stu
drop cascades to type r1
drop cascades to function test_subtype_proc()
--?.*
drop cascades to function plpgsql_recompile.proc1(r1)
drop cascades to function plpgsql_recompile.proc1(s_type)
reset behavior_compat_options;

View File

@ -132,6 +132,77 @@ end pkg;
/
alter package pkg compile;
-- select oid,* from pg_type where typname='stu';
-- test 3
create procedure test_subtype_proc is
xx s_type;
begin
xx := (1,'aaa','bbb');
raise notice '%',xx;
end;
/
call test_subtype_proc();
alter type s_type ADD attribute a int;
--
call test_subtype_proc();
--
alter procedure test_subtype_proc compile;
call test_subtype_proc();
-- test 4
create or replace package pkg
is
procedure proc1();
end pkg;
/
create or replace package body pkg
is
xxx s_type;
procedure proc1() as
yyy s_type;
begin
xxx:= (1,'aaa','aaaaa');
yyy:= (2,'bbb','bbbbb');
RAISE INFO 'call xxx: %, yyy: %', xxx, yyy;
end;
end pkg;
/
call pkg.proc1();
alter type s_type ADD attribute b int;
--
call pkg.proc1();
--
alter package pkg compile;
call pkg.proc1();
-- test 5
create or replace package pkg
is
procedure proc1(p_in s_type);
end pkg;
/
create or replace package body pkg
is
xxx s_type;
procedure proc1(p_in s_type) as
yyy s_type;
begin
xxx:= (1,'aaa','aaaaa');
yyy:= (2,'bbb','bbbbb');
RAISE INFO 'call xxx: %, yyy: %, p_in: %', xxx, yyy, p_in;
end;
end pkg;
/
call pkg.proc1((1,'zhang','M',1,2));
alter type s_type ADD attribute c int;
--
call pkg.proc1((1,'zhang','M',1,2,3));
--
alter package pkg compile;
call pkg.proc1((1,'zhang','M',1,2,3));
-- clean
drop schema plpgsql_recompile cascade;
reset behavior_compat_options;