!4752 处理issue: 存储过程调用default值传给了其他入参

Merge pull request !4752 from lukeman/master
This commit is contained in:
opengauss_bot
2024-01-17 03:28:17 +00:00
committed by Gitee
7 changed files with 138 additions and 8 deletions

View File

@ -39,8 +39,10 @@
static Oid FuncNameAsType(List* funcname);
static Node* ParseComplexProjection(ParseState* pstate, char* funcname, Node* first_arg, int location);
static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs);
static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs, bool* defaultValid);
static Oid cl_get_input_param_original_type(Oid func_oid, int argno);
static bool CheckDefaultArgsPosition(int2vector* defaultargpos, int pronargdefaults, int ndargs,
int pronallargs, int pronargs, HeapTuple procTup);
/*
* Parse a function call
@ -1820,7 +1822,14 @@ FuncDetailCode func_get_detail(List* funcname, List* fargs, List* fargnames, int
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), errmodule(MOD_OPT), errmsg("not enough default arguments")));
*argdefaults = GetDefaultVale(*funcid, best_candidate->argnumbers, best_candidate->ndargs);
bool defaultValid = true;
*argdefaults = GetDefaultVale(*funcid, best_candidate->argnumbers, best_candidate->ndargs, &defaultValid);
if (!defaultValid) {
ereport(DEBUG3,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmodule(MOD_OPT), errmsg("default arguments pos is not right.")));
return FUNCDETAIL_NOTFOUND;
}
}
if (pform->proisagg)
result = FUNCDETAIL_AGGREGATE;
@ -2260,7 +2269,7 @@ Oid LookupAggNameTypeNames(List* aggname, List* argtypes, bool noError)
}
// fetch default args if caller wants 'em
static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs)
static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs, bool* defaultValid)
{
HeapTuple tuple;
Form_pg_proc formproc;
@ -2357,6 +2366,9 @@ static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs)
while (ndelete-- > 0) {
defaults = list_delete_first(defaults);
}
*defaultValid = CheckDefaultArgsPosition(defaultargpos, pronargdefaults, ndargs,
pronallargs, pronargs, tuple);
}
if (argtypes != NULL)
@ -2376,6 +2388,49 @@ static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs)
return defaults;
}
static bool CheckDefaultArgs(int2vector* defaultargpos, int pronargdefaults, int pronallargs,
int pronargs, HeapTuple proctup)
{
if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT || PROC_UNCHECK_DEFAULT_PARAM) {
return true;
}
// if the func has out param, but did not enable_out_param_override, we don't check the defaultpos
if (pronallargs > pronargs && !enable_out_param_override()) {
return true;
}
// the pg_catalog's func can omit out param, so we don't check the defaultpos
bool isnull = false;
Datum namespaceDatum = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_pronamespace, &isnull);
if (!isnull && IsAformatStyleFunctionOid(DatumGetObjectId(namespaceDatum))) {
return true;
}
// if the func has the default args without position, we consider the position is at the end, no error
if (defaultargpos->dim1 == 0 && pronargdefaults > 0) {
return true;
}
return false;
}
/*
* Check whether the parameter is in the appropriate position with default values
*/
static bool CheckDefaultArgsPosition(int2vector* defaultargpos, int pronargdefaults, int ndargs,
int pronallargs, int pronargs, HeapTuple proctup)
{
if (CheckDefaultArgs(defaultargpos, pronargdefaults, pronallargs, pronargs, proctup)) {
return true;
}
// Check whether the defaultpos are at the end of the parameter list from back to front
int argIndex = pronallargs - 1;
int defaultposIndex = pronargdefaults - 1;
for (; argIndex >= pronallargs - ndargs; argIndex--, defaultposIndex--) {
if (defaultargpos->values[defaultposIndex] != argIndex) {
return false;
}
}
return true;
}
/*
* Replace column managed type with original type
* to identify overloaded functions

View File

@ -388,7 +388,8 @@ static const struct behavior_compat_entry behavior_compat_options[OPT_MAX] = {
{"allow_orderby_undistinct_column", OPT_ALLOW_ORDERBY_UNDISTINCT_COLUMN},
{"select_into_return_null", OPT_SELECT_INTO_RETURN_NULL},
{"accept_empty_str", OPT_ACCEPT_EMPTY_STR},
{"plpgsql_dependency", OPT_PLPGSQL_DEPENDENCY}
{"plpgsql_dependency", OPT_PLPGSQL_DEPENDENCY},
{"proc_uncheck_default_param", OPT_PROC_UNCHECK_DEFAULT_PARAM}
};
// increase SQL_IGNORE_STRATEGY_NUM if we need more strategy

View File

@ -203,7 +203,8 @@ extern bool contain_backend_version(uint32 version_number);
#define OPT_SELECT_INTO_RETURN_NULL 67108864
#define OPT_ACCEPT_EMPTY_STR 134217728
#define OPT_PLPGSQL_DEPENDENCY 268435456
#define OPT_MAX 29
#define OPT_PROC_UNCHECK_DEFAULT_PARAM 536870912
#define OPT_MAX 30
#define PLPSQL_OPT_FOR_LOOP 1
#define PLPSQL_OPT_OUTPARAM 2
@ -246,6 +247,7 @@ extern bool contain_backend_version(uint32 version_number);
#define SELECT_INTO_RETURN_NULL (u_sess->utils_cxt.behavior_compat_flags & OPT_SELECT_INTO_RETURN_NULL)
#define PLPGSQL_DEPENDENCY (u_sess->utils_cxt.behavior_compat_flags & OPT_PLPGSQL_DEPENDENCY)
#define PROC_UNCHECK_DEFAULT_PARAM (u_sess->utils_cxt.behavior_compat_flags & OPT_PROC_UNCHECK_DEFAULT_PARAM)
/* define database compatibility Attribute */
typedef struct {

View File

@ -0,0 +1,47 @@
drop schema if exists function_default cascade;
NOTICE: schema "function_default" does not exist, skipping
create schema function_default;
set current_schema = function_default;
show behavior_compat_options;
behavior_compat_options
-------------------------
(1 row)
-- 创建存储过程
create or replace procedure pro_default(p1 text,p2 int default 123,p3 int)
as
begin
raise info 'p1:%',p1;
raise info 'p2:%',p2;
raise info 'p3:%',p3;
end;
/
-- 调用存储过程,预期报错
call pro_default('test',1);
ERROR: function pro_default(unknown, integer) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- 开启逃生参数,保持原本表现
set behavior_compat_options="proc_uncheck_default_param";
show behavior_compat_options;
behavior_compat_options
----------------------------
proc_uncheck_default_param
(1 row)
call pro_default('test',1);
INFO: p1:test
INFO: p2:1
INFO: p3:123
pro_default
-------------
(1 row)
-- 清理环境
drop schema function_default cascade;
NOTICE: drop cascades to function pro_default(text,integer,integer)
reset behavior_compat_options;

View File

@ -760,7 +760,7 @@ test: plpgsql_assign_value_to_array_attribute
test: plpgsql_array_of_record
#test: plpgsql_nest_compile
test: arrayinterface_ted
test: plpgsql_inout_param record_slow_sql_in_proc
test: function_default_test plpgsql_inout_param record_slow_sql_in_proc
test: plpgsql_cursor_rowtype
test: plpgsql_assign_list
test: plpgsql_package_type plpgsql_package_param

View File

@ -277,7 +277,7 @@ test: plpgsql_assign_value_to_array_attribute
test: plpgsql_array_of_record
#test: plpgsql_nest_compile
test: arrayinterface_ted
test: plpgsql_inout_param
test: function_default_test plpgsql_inout_param
test: plpgsql_cursor_rowtype
test: plpgsql_assign_list
test: plpgsql_package_type plpgsql_package_param

View File

@ -0,0 +1,25 @@
drop schema if exists function_default cascade;
create schema function_default;
set current_schema = function_default;
show behavior_compat_options;
-- 创建存储过程
create or replace procedure pro_default(p1 text,p2 int default 123,p3 int)
as
begin
raise info 'p1:%',p1;
raise info 'p2:%',p2;
raise info 'p3:%',p3;
end;
/
-- 调用存储过程,预期报错
call pro_default('test',1);
-- 开启逃生参数,保持原本表现
set behavior_compat_options="proc_uncheck_default_param";
show behavior_compat_options;
call pro_default('test',1);
-- 清理环境
drop schema function_default cascade;
reset behavior_compat_options;