diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index b5ac29bab..c8fb857bb 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -106,6 +106,8 @@ static void plpgsql_parser_funcname(const char *s, char **output, int numidents); static PLpgSQL_stmt *make_callfunc_stmt(const char *sqlstart, int location, bool is_assign); + +static PLpgSQL_stmt *make_callfunc_stmt_no_arg(const char *sqlstart, int location); static PLpgSQL_expr *read_sql_construct5(int until, int until2, @@ -2343,23 +2345,36 @@ stmt_execsql : K_ALTER { int tok = -1; bool isCallFunc = false; + bool funcNoarg = false; + tok = yylex(); if ('(' == tok) isCallFunc = is_function($1.ident, false); else if ('=' ==tok || COLON_EQUALS == tok || '[' == tok) word_is_not_variable(&($1), @1); + else if (';' == tok) + funcNoarg = true; - plpgsql_push_back_token(tok); - if (isCallFunc) - $$ = make_callfunc_stmt($1.ident, @1, false); - else - $$ = make_execsql_stmt(T_WORD, @1); + if (funcNoarg) { + isCallFunc = is_function($1.ident, false); + if (isCallFunc) + $$ = make_callfunc_stmt_no_arg($1.ident, @1); + else + $$ = make_execsql_stmt(T_WORD, @1); + } else { + plpgsql_push_back_token(tok); + if (isCallFunc) + $$ = make_callfunc_stmt($1.ident, @1, false); + else + $$ = make_execsql_stmt(T_WORD, @1); + } } | T_CWORD { int tok = yylex(); char *name = NULL; bool isCallFunc = false; + bool funcNoarg = false; if ('(' == tok) { @@ -2370,12 +2385,26 @@ stmt_execsql : K_ALTER } else if ('=' == tok || COLON_EQUALS == tok || '[' == tok) cword_is_not_variable(&($1), @1); + else if (';' == tok) { + MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); + name = NameListToString($1.idents); + (void)MemoryContextSwitchTo(colCxt); + isCallFunc = is_function(name, false); + funcNoarg = true; + } - plpgsql_push_back_token(tok); - if (isCallFunc) - $$ = make_callfunc_stmt(name, @1, false); - else - $$ = make_execsql_stmt(T_CWORD, @1); + if (funcNoarg) { + if (isCallFunc) + $$ = make_callfunc_stmt_no_arg(name, @1); + else + $$ = make_execsql_stmt(T_CWORD, @1); + } else { + plpgsql_push_back_token(tok); + if (isCallFunc) + $$ = make_callfunc_stmt(name, @1, false); + else + $$ = make_execsql_stmt(T_CWORD, @1); + } } | T_ARRAY_EXTEND { @@ -5924,3 +5953,72 @@ make_case(int location, PLpgSQL_expr *t_expr, return (PLpgSQL_stmt *) newp; } + +static PLpgSQL_stmt * +make_callfunc_stmt_no_arg(const char *sqlstart, int location) +{ + char *cp[3]; + + List *funcname = NIL; + PLpgSQL_expr* expr = NULL; + FuncCandidateList clist = NULL; + StringInfoData func_inparas; + char *quoted_sqlstart = NULL; + + MemoryContext oldCxt = NULL; + /*get the function's name*/ + cp[0] = NULL; + cp[1] = NULL; + cp[2] = NULL; + /* the function make_callfunc_stmt is only to assemble a sql statement, so the context is set to tmp context */ + oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); + plpgsql_parser_funcname(sqlstart, cp, 3); + + if (cp[2] && cp[2][0] != '\0') + funcname = list_make3(makeString(cp[0]), makeString(cp[1]), makeString(cp[2])); + else if (cp[1] && cp[1][0] != '\0') + funcname = list_make2(makeString(cp[0]), makeString(cp[1])); + else + funcname = list_make1(makeString(cp[0])); + + + /* search the function */ + clist = FuncnameGetCandidates(funcname, -1, NIL, false, false, false); + if (!clist) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function \"%s\" doesn't exist ", sqlstart))); + return NULL; + } + + initStringInfo(&func_inparas); + + appendStringInfoString(&func_inparas, "CALL "); + + quoted_sqlstart = NameListToQuotedString(funcname); + appendStringInfoString(&func_inparas, quoted_sqlstart); + pfree_ext(quoted_sqlstart); + + appendStringInfoString(&func_inparas, "("); + + appendStringInfoString(&func_inparas, ")"); + + (void)MemoryContextSwitchTo(oldCxt); + + /* generate the expression */ + expr = (PLpgSQL_expr*)palloc0(sizeof(PLpgSQL_expr)); + expr->dtype = PLPGSQL_DTYPE_EXPR; + expr->query = pstrdup(func_inparas.data); + expr->plan = NULL; + expr->paramnos = NULL; + expr->ns = plpgsql_ns_top(); + + PLpgSQL_stmt_perform *perform = NULL; + perform = (PLpgSQL_stmt_perform*)palloc0(sizeof(PLpgSQL_stmt_perform)); + perform->cmd_type = PLPGSQL_STMT_PERFORM; + perform->lineno = plpgsql_location_to_lineno(location); + perform->expr = expr; + + return (PLpgSQL_stmt *)perform; +} \ No newline at end of file diff --git a/src/test/regress/expected/hw_procedure.out b/src/test/regress/expected/hw_procedure.out index 932aca1a4..e7bf9f868 100644 --- a/src/test/regress/expected/hw_procedure.out +++ b/src/test/regress/expected/hw_procedure.out @@ -578,9 +578,6 @@ BEGIN return q; END; $$ LANGUAGE plpgsql; -ERROR: syntax error at or near "hw_insertion5" -LINE 5: hw_insertion5; --IN, INOUT - ^ CREATE FUNCTION test_func_call_less_arg6() RETURNS integer AS $$ DECLARE q int := 1; @@ -1884,3 +1881,59 @@ END; / drop table test_table; +-----------------------------------------------------function without arguments +DROP FUNCTION IF EXISTS func_add_sql_arg2; +NOTICE: function func_add_sql_arg2() does not exist, skipping +DROP function IF EXISTS f_add_no_arg; +NOTICE: function f_add_no_arg() does not exist, skipping +DROP FUNCTION IF EXISTS f_add; +NOTICE: function f_add() does not exist, skipping +CREATE FUNCTION func_add_sql_arg2(num1 integer, num2 integer) RETURN integer +AS +BEGIN +RETURN num1 + num2; +END; +/ +CREATE FUNCTION func_add_sql_no_arg() RETURN integer +AS +BEGIN +RETURN 1; +END; +/ +create or replace procedure f_add_no_arg +as +begin + func_add_sql_arg2; +end; +/ +create or replace procedure f_add +as +begin + func_add_sql_arg2(3,4); +end; +/ +call f_add(); + f_add +------- + +(1 row) + +call f_add_no_arg(); +ERROR: function "func_add_sql_arg2" with 0 parameters doesn't exist +CONTEXT: SQL statement "CALL func_add_sql_arg2()" +PL/pgSQL function f_add_no_arg() line 3 at PERFORM +DROP FUNCTION IF EXISTS func_add_sql_arg2; +DROP function IF EXISTS f_add_no_arg; +DROP FUNCTION IF EXISTS f_add; +create or replace procedure func_proc_no_arg +as +begin + func_add_sql_no_arg; +end; +/ +call func_proc_no_arg(); + func_proc_no_arg +------------------ + +(1 row) + diff --git a/src/test/regress/sql/hw_procedure.sql b/src/test/regress/sql/hw_procedure.sql index 81ee6af7f..9951bf73c 100644 --- a/src/test/regress/sql/hw_procedure.sql +++ b/src/test/regress/sql/hw_procedure.sql @@ -1586,3 +1586,54 @@ END; / drop table test_table; + + + +-----------------------------------------------------function without arguments +DROP FUNCTION IF EXISTS func_add_sql_arg2; +DROP function IF EXISTS f_add_no_arg; +DROP FUNCTION IF EXISTS f_add; + +CREATE FUNCTION func_add_sql_arg2(num1 integer, num2 integer) RETURN integer +AS +BEGIN +RETURN num1 + num2; +END; +/ + +CREATE FUNCTION func_add_sql_no_arg() RETURN integer +AS +BEGIN +RETURN 1; +END; +/ + +create or replace procedure f_add_no_arg +as +begin + func_add_sql_arg2; +end; +/ + +create or replace procedure f_add +as +begin + func_add_sql_arg2(3,4); +end; +/ + +call f_add(); +call f_add_no_arg(); + +DROP FUNCTION IF EXISTS func_add_sql_arg2; +DROP function IF EXISTS f_add_no_arg; +DROP FUNCTION IF EXISTS f_add; + +create or replace procedure func_proc_no_arg +as +begin + func_add_sql_no_arg; +end; +/ + +call func_proc_no_arg(); \ No newline at end of file