diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index 38d762bde..bc5f4667b 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -12777,10 +12777,11 @@ parse_datatype(const char *string, int location) { Oid type_id; int32 typmod; + int expr_len = 0; sql_error_callback_arg cbarg; ErrorContextCallback syntax_errcontext; MemoryContext oldCxt = NULL; - + PLpgSQL_type* datatype = NULL; cbarg.location = location; cbarg.leaderlen = 0; @@ -12827,11 +12828,13 @@ parse_datatype(const char *string, int location) /* Okay, build a PLpgSQL_type data structure for it */ if (u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile == NULL) { - return plpgsql_build_datatype(type_id, typmod, 0, typeDependExtend); - } - - return plpgsql_build_datatype(type_id, typmod, + datatype = plpgsql_build_datatype(type_id, typmod, 0, typeDependExtend); + } else { + datatype = plpgsql_build_datatype(type_id, typmod, u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile->fn_input_collation, typeDependExtend); + } + datatype->defaultvalues = get_default_plpgsql_expr_from_typeoid(type_id, &expr_len); + return datatype; } /* Build a arrary_type by elem_type. */ @@ -13546,7 +13549,7 @@ static Node* make_columnDef_from_attr(PLpgSQL_rec_attr* attr) n->is_not_null = false; n->is_from_type = false; n->storage = 0; - n->raw_default = NULL; + n->raw_default = attr->defaultvalue ? get_default_node_from_plpgsql_expr(attr->defaultvalue) : NULL; n->cooked_default = NULL; n->collClause = NULL; n->clientLogicColumnRef=NULL; diff --git a/src/common/pl/plpgsql/src/pl_comp.cpp b/src/common/pl/plpgsql/src/pl_comp.cpp index 249f9b0b8..85fc03f31 100644 --- a/src/common/pl/plpgsql/src/pl_comp.cpp +++ b/src/common/pl/plpgsql/src/pl_comp.cpp @@ -28,6 +28,7 @@ #include "catalog/gs_package.h" #include "catalog/gs_package_fn.h" #include "catalog/pg_type.h" +#include "catalog/pg_attrdef.h" #include "commands/sqladvisor.h" #include "executor/spi.h" #include "funcapi.h" @@ -90,7 +91,7 @@ static Node* plpgsql_post_column_ref(ParseState* pstate, ColumnRef* cref, Node* static Node* plpgsql_param_ref(ParseState* pstate, ParamRef* pref); static Node* resolve_column_ref(ParseState* pstate, PLpgSQL_expr* expr, ColumnRef* cref, bool error_if_no_field); static Node* make_datum_param(PLpgSQL_expr* expr, int dno, int location); -extern PLpgSQL_row* build_row_from_class(Oid class_oid); +extern PLpgSQL_row* build_row_from_class(Oid class_oid, PLpgSQL_expr** defaultvalues); static PLpgSQL_row* build_row_from_vars(PLpgSQL_variable** vars, int numvars); static void compute_function_hashkey(HeapTuple proc_tup, FunctionCallInfo fcinfo, Form_pg_proc proc_struct, PLpgSQL_func_hashkey* hashkey, bool for_validator); @@ -675,6 +676,28 @@ static bool CheckPipelinedResIsTuple(Form_pg_type type_struct) { return pipelinedResIsTuple; } +static void plpgsql_add_param_initdatums(int *newvarnos, int newnum, int** oldvarnos, int oldnum) +{ + int i; + int n = 0; + int *varnos = NULL; + errno_t rc = 0; + varnos = (int*)palloc(sizeof(int) * (newnum + oldnum)); + + if (oldnum > 0) { + rc = memcpy_s(varnos, sizeof(int) * oldnum, (int*)(*oldvarnos), sizeof(int) * oldnum); + securec_check(rc, "", ""); + } + if (newnum > 0) { + rc = memcpy_s(varnos + oldnum, sizeof(int) * newnum, newvarnos, sizeof(int) * newnum); + securec_check(rc, "", ""); + } + + if (*oldvarnos) + pfree(*oldvarnos); + *oldvarnos = varnos; +} + /* * This is the slow part of plpgsql_compile(). * @@ -723,7 +746,8 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, PLpgSQL_variable** out_arg_variables; Oid pkgoid = InvalidOid; Oid namespaceOid = InvalidOid; - + int *allvarnos = NULL; + int n_varnos = 0; Oid* saved_pseudo_current_userId = NULL; char* signature = NULL; @@ -1006,6 +1030,7 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, const int buf_size = 32; char buf[buf_size]; Oid arg_type_id = arg_types[i]; + int attrnum = 0; char arg_mode = arg_modes ? arg_modes[i] : PROARGMODE_IN; PLpgSQL_variable* argvariable = NULL; int arg_item_type; @@ -1020,6 +1045,9 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, /* Create datatype info */ PLpgSQL_type* argdtype = plpgsql_build_datatype(arg_type_id, -1, func->fn_input_collation); + if (arg_mode != PROARGMODE_IN && arg_mode != PROARGMODE_INOUT) { + argdtype->defaultvalues = get_default_plpgsql_expr_from_typeoid(arg_type_id, &attrnum); + } /* Disallow pseudotype argument */ /* (note we already replaced polymorphic types) */ @@ -1034,6 +1062,11 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, } else { argvariable = plpgsql_build_variable(buf, 0, argdtype, false); } + if (argdtype->defaultvalues) { + PLpgSQL_row *row = (PLpgSQL_row *)argvariable; + plpgsql_add_param_initdatums(row->varnos, attrnum, &allvarnos, n_varnos); + n_varnos = n_varnos + attrnum; + } if (argvariable->dtype == PLPGSQL_DTYPE_VAR) { arg_item_type = PLPGSQL_NSTYPE_VAR; @@ -1421,6 +1454,10 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, errmsg("Syntax parsing error, plpgsql parser returned %d", parse_rc))); } func->action = curr_compile->plpgsql_parse_result; + if (n_varnos > 0) { + plpgsql_add_param_initdatums(allvarnos, n_varnos, &func->action->initvarnos, func->action->n_initvars); + func->action->n_initvars = func->action->n_initvars + n_varnos; + } if (is_dml_trigger && func->action->isAutonomous) { ereport(ERROR, @@ -3929,7 +3966,7 @@ PLpgSQL_variable* plpgsql_build_variable(const char* refname, int lineno, PLpgSQ /* Composite type -- build a row variable */ PLpgSQL_row* row = NULL; - row = build_row_from_class(dtype->typrelid); + row = build_row_from_class(dtype->typrelid, dtype->defaultvalues); row->addNamespace = add2namespace; row->customErrorCode = 0; if (0 == strcmp(format_type_be(row->rowtupdesc->tdtypeid), "exception")) { @@ -4313,7 +4350,7 @@ void plpgsql_build_synonym(char* typname, char* basetypname) /* * Build a row-variable data structure given the pg_class OID. */ -PLpgSQL_row* build_row_from_class(Oid class_oid) +PLpgSQL_row* build_row_from_class(Oid class_oid, PLpgSQL_expr** defaultvalues) { /* * Open the relation to get info. @@ -4374,6 +4411,8 @@ PLpgSQL_row* build_row_from_class(Oid class_oid) */ var = plpgsql_build_variable(refname, 0, plpgsql_build_datatype(attr_struct->atttypid, attr_struct->atttypmod, attr_struct->attcollation), false); + if (defaultvalues != NULL) + ((PLpgSQL_var*)var)->default_val = defaultvalues[i]; /* Add the variable to the row */ row->fieldnames[i] = attname; @@ -4637,7 +4676,7 @@ PLpgSQL_type* build_datatype(HeapTuple type_tup, int32 typmod, Oid collation) errmsg("type \"%s\" is only a shell when build data type in PLSQL.", NameStr(type_struct->typname)))); } PLpgSQL_type* typ = (PLpgSQL_type*)palloc(sizeof(PLpgSQL_type)); - + typ->defaultvalues = NULL; typ->typname = pstrdup(NameStr(type_struct->typname)); typ->typoid = HeapTupleGetOid(type_tup); typ->collectionType = PLPGSQL_COLLECTION_NONE; @@ -5947,3 +5986,106 @@ void checkArrayTypeInsert(ParseState* pstate, Expr* expr) } } } + +Node* get_default_node_from_plpgsql_expr(PLpgSQL_expr *expr) +{ + MemoryContext cur = CurrentMemoryContext; + MemoryContext temp = NULL; + CachedPlanSource* plansource = NULL; + SelectStmt* stmt = NULL; + Value *val = NULL; + _SPI_plan plan; + parse_query_func parser = GetRawParser(); + + if (expr->query == NULL) { + return NULL; + } + + SPI_STACK_LOG("connect", NULL, NULL); + if (SPI_connect() != SPI_OK_CONNECT) { + ereport(ERROR, (errcode(ERRCODE_SPI_CONNECTION_FAILURE), errmsg("SPI_connect failed"))); + } + SPI_STACK_LOG("begin", expr->query, NULL); + if (_SPI_begin_call(true) < 0) { + return NULL; + } + + int rc = memset_s(&plan, sizeof(_SPI_plan), '\0', sizeof(_SPI_plan)); + securec_check_c(rc, "\0", "\0"); + plan.magic = _SPI_PLAN_MAGIC; + plan.cursor_options = 0; + plan.spi_key = INVALID_SPI_KEY; + + _SPI_prepare_oneshot_plan(expr->query, &plan, parser); + plansource = (CachedPlanSource*)lfirst(plan.plancache_list->head); + stmt = (SelectStmt*)plansource->raw_parse_tree; + if (stmt->targetList) { + Node* node = (Node*)lfirst(stmt->targetList->head); + if (IsA(node, ResTarget)) { + ResTarget* resTarget = (ResTarget*)node; + temp = MemoryContextSwitchTo(cur); + val = (Value*)copyObject((void*)resTarget->val); + temp = MemoryContextSwitchTo(temp); + } + } + + if (_SPI_end_call(true) < 0) { + return NULL; + } + SPI_STACK_LOG("finish", NULL, NULL); + if (SPI_finish() != SPI_OK_FINISH) { + ereport(ERROR, (errcode(ERRCODE_SPI_FINISH_FAILURE), errmsg("SPI_finish failed"))); + } + return (Node*)val; +} + +PLpgSQL_expr** get_default_plpgsql_expr_from_typeoid(Oid typeOid, int* attrnum) +{ + PLpgSQL_expr** defaultvalues = NULL; + ScanKeyData skey; + HeapTuple htup; + bool isnull = false; + Datum typrelid = typeidTypeRelid(typeOid); + if (typrelid != InvalidOid) { + ScanKeyInit(&skey, Anum_pg_attrdef_adrelid, BTEqualStrategyNumber, F_OIDEQ, typrelid); + Relation adrel = heap_open(AttrDefaultRelationId, AccessShareLock); + SysScanDesc adscan = systable_beginscan(adrel, AttrDefaultIndexId, true, NULL, 1, &skey); + List* del_list = NIL; + ListCell *lc = NULL; + int i = 0, j = 0; + while (HeapTupleIsValid(htup = systable_getnext(adscan))) { + Form_pg_attrdef adform = (Form_pg_attrdef)GETSTRUCT(htup); + Datum val; + StringInfoData ds; + val = fastgetattr(htup, Anum_pg_attrdef_adsrc, adrel->rd_att, &isnull); + char *adsrc_str = isnull ? NULL : TextDatumGetCString(val); + initStringInfo(&ds); + appendStringInfoString(&ds, "SELECT "); + appendStringInfoString(&ds, adsrc_str); + del_list = lappend(del_list, ds.data); + j++; + } + *attrnum = j; + if (j > 0) { + defaultvalues = (PLpgSQL_expr **)palloc0(sizeof(PLpgSQL_expr *) * j); + PLpgSQL_expr *exprs = (PLpgSQL_expr *)palloc0(sizeof(PLpgSQL_expr) * j); + foreach (lc, del_list) { + char *query = (char *)lfirst(lc); + PLpgSQL_expr *expr = exprs + i; + expr->dtype = PLPGSQL_DTYPE_EXPR; + expr->query = pstrdup(query); + expr->plan = NULL; + expr->paramnos = NULL; + expr->isouttype = false; + expr->idx = UINT32_MAX; + expr->out_param_dno = -1; + expr->is_have_tableof_index_func = true; + defaultvalues[i] = expr; + i++; + } + } + systable_endscan(adscan); + heap_close(adrel, AccessShareLock); + } + return defaultvalues; +} diff --git a/src/include/utils/pl_package.h b/src/include/utils/pl_package.h index b82fb4cd8..ab23fe06a 100644 --- a/src/include/utils/pl_package.h +++ b/src/include/utils/pl_package.h @@ -49,7 +49,7 @@ extern Oid findPackageParameter(const char* objname); extern int plpgsql_getCustomErrorCode(void); -extern PLpgSQL_row* build_row_from_class(Oid class_oid); +extern PLpgSQL_row* build_row_from_class(Oid class_oid, PLpgSQL_expr** defaultvalues); extern int GetLineNumber(const char* procedureStr, int loc); diff --git a/src/include/utils/plpgsql.h b/src/include/utils/plpgsql.h index c6b330969..3d14b6e75 100644 --- a/src/include/utils/plpgsql.h +++ b/src/include/utils/plpgsql.h @@ -489,6 +489,7 @@ typedef struct { /* openGauss data type */ PLpgSQL_expr* cursorExpr; int cursorDno; char typtyp; + PLpgSQL_expr** defaultvalues; } PLpgSQL_type; typedef struct { @@ -1858,6 +1859,8 @@ extern PLpgSQL_datum* plpgsql_lookup_datum( extern PLpgSQL_type* plpgsql_get_row_field_type(int dno, const char* fieldname, MemoryContext old_cxt); extern PLpgSQL_resolve_option GetResolveOption(); extern Node* plpgsql_check_match_var(Node* node, ParseState* pstate, ColumnRef* cref); +extern Node* get_default_node_from_plpgsql_expr(PLpgSQL_expr *expr); +extern PLpgSQL_expr** get_default_plpgsql_expr_from_typeoid(Oid typeOid, int* attrnum); /* ---------- * Functions in pl_handler.c diff --git a/src/test/regress/expected/plpgsql_default_value_various_type.out b/src/test/regress/expected/plpgsql_default_value_various_type.out new file mode 100644 index 000000000..1baadccb9 --- /dev/null +++ b/src/test/regress/expected/plpgsql_default_value_various_type.out @@ -0,0 +1,446 @@ +create schema test_pkg_default_value; +set current_schema = test_pkg_default_value; +-- test default expr +CREATE FUNCTION func1(num2 inout int,num3 inout int) RETURNS int +AS $$ +DECLARE +BEGIN +num2 := num2 + 9 + num3; +return num2; +END +$$ +LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION func3(num2 inout int) RETURNS int +AS $$ +DECLARE +BEGIN +num2 := num2 + 2; +return num2; +END +$$ +LANGUAGE plpgsql; +CREATE FUNCTION func2(num1 inout int, st1 inout varchar(10), num2 inout int) RETURNS int +AS $$ +DECLARE +BEGIN + num2 := num2 + 9; + raise info 'str1 is %', NVL(str1,'NULL'); + raise info 'str2 is %', NVL(str2,'NULL'); + raise info 'num1 is %', num1; + raise info 'num2 is %', num2; +return num2; +END +$$ +LANGUAGE plpgsql; +CREATE FUNCTION func4(num2 inout int,num3 inout bool) RETURNS int +AS $$ +DECLARE +BEGIN +num2 := num2 + 1; +return num2; +END +$$ +LANGUAGE plpgsql; +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (+1)); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + adsrc +------- + (+ 1) +(1 row) + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ +INFO: r1.f is 1 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := 1+-9+8*(-7)+1*-2); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + adsrc +------------------------------------------ + (((1 + (-9)) + (8 * (-7))) + (1 * (-2))) +(1 row) + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ +INFO: r1.f is -66 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := 1+-9+8/-11*(-7)+1*-2*2/5); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + adsrc +-------------------------------------------------------------------------------------------------------- + ((((1 + (-9)))::double precision + ((8 / (-11)) * ((-7))::double precision)) + (((1 * (-2)) * 2) / 5)) +(1 row) + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ +INFO: r1.f is -4 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := 8*-11*(-7)+1*-2*2/5+9); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + adsrc +----------------------------------------------------------------------------------------------- + (((((8 * (-11)) * (-7)))::double precision + (((1 * (-2)) * 2) / 5)) + (9)::double precision) +(1 row) + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ +INFO: r1.f is 624 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := -1); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + adsrc +------- + (-1) +(1 row) + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ +INFO: r1.f is -1 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abus'); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + adsrc +--------------------------- + 'abus'::character varying +(1 row) + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', NVL(r1.f,'NULL'); +END; +/ +INFO: r1.f is abus +-- test expr error +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (1+)); +END r_types; +/ +ERROR: syntax error at or near ")" +LINE 1: SELECT (1+) + ^ +QUERY: SELECT (1+) +CONTEXT: compilation of PL/pgSQL package near line 1 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := +); +END r_types; +/ +ERROR: syntax error at end of input +LINE 1: SELECT + + ^ +QUERY: SELECT + +CONTEXT: compilation of PL/pgSQL package near line 1 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (+)); +END r_types; +/ +ERROR: syntax error at or near "(+)" +LINE 1: SELECT (+) + ^ +QUERY: SELECT (+) +CONTEXT: compilation of PL/pgSQL package near line 1 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (a+b)); +END r_types; +/ +ERROR: column "a" does not exist +CONTEXT: compilation of PL/pgSQL package near line 1 +-- normal default +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abcde', f2 VARCHAR2(5) := 'waxtr'); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f VARCHAR2(5) := 'a1c2e', f2 VARCHAR2(5) := 'w5x3r'); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', NVL(r1.f,'NULL'); + raise info 'r1.f2 is %', NVL(r1.f2,'NULL'); + raise info 'r2.f is %', NVL(r2.f,'NULL'); + raise info 'r1.f2 is %', NVL(r2.f2,'NULL'); +END; +/ +INFO: r1.f is abcde +INFO: r1.f2 is waxtr +INFO: r2.f is a1c2e +INFO: r1.f2 is w5x3r +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f date := '2001-9-28', f2 timestamp := '1957-06-13'); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f date := '2000-7-28', f2 timestamp := '1987-06-03'); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ +INFO: r1.f is Fri Sep 28 00:00:00 2001 +INFO: r1.f2 is Thu Jun 13 00:00:00 1957 +INFO: r1.f is Fri Jul 28 00:00:00 2000 +INFO: r1.f2 is Wed Jun 03 00:00:00 1987 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f boolean := true, f2 numeric := 19.578); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f boolean := false, f2 numeric := 13.278); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ +INFO: r1.f is t +INFO: r1.f2 is 19.578 +INFO: r1.f is f +INFO: r1.f2 is 13.278 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f money := 10.5, f2 int := 15); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f money := 9.6, f2 int := 13); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ +INFO: r1.f is $10.50 +INFO: r1.f2 is 15 +INFO: r1.f is $9.60 +INFO: r1.f2 is 13 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f integer := 10, f2 oid := 15); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f integer := 9, f2 oid := 13); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ +INFO: r1.f is 10 +INFO: r1.f2 is 15 +INFO: r1.f is 9 +INFO: r1.f2 is 13 +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f name := 'abcde', f2 text := 'waxtr'); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f name := 'a1c2e', f2 text := 'w5x3r'); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', NVL(r1.f,'NULL'); + raise info 'r1.f2 is %', NVL(r1.f2,'NULL'); + raise info 'r2.f is %', NVL(r2.f,'NULL'); + raise info 'r1.f2 is %', NVL(r2.f2,'NULL'); +END; +/ +INFO: r1.f is abcde +INFO: r1.f2 is waxtr +INFO: r2.f is a1c2e +INFO: r1.f2 is w5x3r +-- pkg param default +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abcde', f2 VARCHAR2(5) := 'syutw'); + TYPE r_type_2 IS RECORD (f VARCHAR2(5)); +END r_types; +/ +CREATE OR REPLACE PROCEDURE p1 ( + x OUT r_types.r_type_1, + y OUT r_types.r_type_2, + z OUT VARCHAR2) +AUTHID CURRENT_USER IS +BEGIN + raise info 'x.f is %', NVL(x.f,'NULL'); + raise info 'x.f2 is %', NVL(x.f2,'NULL'); + raise info 'y.f is %', NVL(y.f,'NULL'); + raise info 'z is %', NVL(z,'NULL'); +END; +/ +CREATE OR REPLACE PROCEDURE p2 ( + x IN r_types.r_type_1, + y IN r_types.r_type_2, + z IN VARCHAR2) +AUTHID CURRENT_USER IS +BEGIN + raise info 'x.f is %', NVL(x.f,'NULL'); + raise info 'x.f2 is %', NVL(x.f2,'NULL'); + raise info 'y.f is %', NVL(y.f,'NULL'); + raise info 'z is %', NVL(z,'NULL'); +END; +/ +CREATE OR REPLACE PROCEDURE p3 ( + x INOUT r_types.r_type_1, + y INOUT r_types.r_type_2, + z INOUT VARCHAR2) +AUTHID CURRENT_USER IS +BEGIN + raise info 'x.f is %', NVL(x.f,'NULL'); + raise info 'x.f2 is %', NVL(x.f2,'NULL'); + raise info 'y.f is %', NVL(y.f,'NULL'); + raise info 'z is %', NVL(z,'NULL'); +END; +/ +DECLARE + r1 r_types.r_type_1; + r2 r_types.r_type_2; + s VARCHAR2(5) := 'fghij'; +BEGIN + raise info '===============p1==================='; + p1 (r1, r2, s); + raise info '===============p2==================='; + p2 (r1, r2, s); + raise info '===============p3==================='; + p3 (r1, r2, s); + r1.f:='waqrt'; + r1.f2:='bfgrf'; + r2.f:='nuytg'; + raise info '===============p1==================='; + p1 (r1, r2, s); + raise info '===============p2==================='; + p2 (r1, r2, s); + raise info '===============p3==================='; + p3 (r1, r2, s); +END; +/ +INFO: ===============p1=================== +INFO: x.f is abcde +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 6 at SQL statement +INFO: x.f2 is syutw +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 6 at SQL statement +INFO: y.f is NULL +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 6 at SQL statement +INFO: z is NULL +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 6 at SQL statement +INFO: ===============p2=================== +INFO: x.f is abcde +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 8 at PERFORM +INFO: x.f2 is syutw +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 8 at PERFORM +INFO: y.f is NULL +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 8 at PERFORM +INFO: z is NULL +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 8 at PERFORM +INFO: ===============p3=================== +INFO: x.f is abcde +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 10 at SQL statement +INFO: x.f2 is syutw +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 10 at SQL statement +INFO: y.f is NULL +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 10 at SQL statement +INFO: z is NULL +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 10 at SQL statement +INFO: ===============p1=================== +INFO: x.f is abcde +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 15 at SQL statement +INFO: x.f2 is syutw +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 15 at SQL statement +INFO: y.f is NULL +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 15 at SQL statement +INFO: z is NULL +CONTEXT: SQL statement "CALL p1(r1,r2,s)" +PL/pgSQL function inline_code_block line 15 at SQL statement +INFO: ===============p2=================== +INFO: x.f is abcde +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 17 at PERFORM +INFO: x.f2 is syutw +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 17 at PERFORM +INFO: y.f is NULL +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 17 at PERFORM +INFO: z is NULL +CONTEXT: SQL statement "CALL p2(r1,r2,s)" +PL/pgSQL function inline_code_block line 17 at PERFORM +INFO: ===============p3=================== +INFO: x.f is abcde +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 19 at SQL statement +INFO: x.f2 is syutw +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 19 at SQL statement +INFO: y.f is NULL +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 19 at SQL statement +INFO: z is NULL +CONTEXT: SQL statement "CALL p3(r1,r2,s)" +PL/pgSQL function inline_code_block line 19 at SQL statement +DROP FUNCTION func1; +DROP FUNCTION func2; +DROP FUNCTION func3; +DROP FUNCTION func4; +DROP PACKAGE r_types; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to function p1() +--?.* +--?.* +DROP SCHEMA test_pkg_default_value; diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 9861b060e..a8d2eb8ae 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -783,6 +783,7 @@ test: plpgsql_array_of_record test: arrayinterface_ted test: function_default_test plpgsql_inout_param record_slow_sql_in_proc test: plpgsql_cursor_rowtype +test: plpgsql_default_value_various_type test: plpgsql_assign_list test: plpgsql_package_type plpgsql_package_param test: plpgsql_record_attrname diff --git a/src/test/regress/parallel_schedule0B b/src/test/regress/parallel_schedule0B index f54b93595..0e8159456 100644 --- a/src/test/regress/parallel_schedule0B +++ b/src/test/regress/parallel_schedule0B @@ -285,6 +285,7 @@ test: plpgsql_array_of_record test: arrayinterface_ted test: function_default_test plpgsql_inout_param test: plpgsql_cursor_rowtype +test: plpgsql_default_value_various_type test: plpgsql_assign_list test: plpgsql_package_type plpgsql_package_param test: plpgsql_record_attrname diff --git a/src/test/regress/sql/plpgsql_default_value_various_type.sql b/src/test/regress/sql/plpgsql_default_value_various_type.sql new file mode 100644 index 000000000..5aa262efb --- /dev/null +++ b/src/test/regress/sql/plpgsql_default_value_various_type.sql @@ -0,0 +1,318 @@ +create schema test_pkg_default_value; +set current_schema = test_pkg_default_value; + +-- test default expr +CREATE FUNCTION func1(num2 inout int,num3 inout int) RETURNS int +AS $$ +DECLARE +BEGIN +num2 := num2 + 9 + num3; +return num2; +END +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION func3(num2 inout int) RETURNS int +AS $$ +DECLARE +BEGIN +num2 := num2 + 2; +return num2; +END +$$ +LANGUAGE plpgsql; + +CREATE FUNCTION func2(num1 inout int, st1 inout varchar(10), num2 inout int) RETURNS int +AS $$ +DECLARE +BEGIN + num2 := num2 + 9; + raise info 'str1 is %', NVL(str1,'NULL'); + raise info 'str2 is %', NVL(str2,'NULL'); + raise info 'num1 is %', num1; + raise info 'num2 is %', num2; +return num2; +END +$$ +LANGUAGE plpgsql; + +CREATE FUNCTION func4(num2 inout int,num3 inout bool) RETURNS int +AS $$ +DECLARE +BEGIN +num2 := num2 + 1; +return num2; +END +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (+1)); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := 1+-9+8*(-7)+1*-2); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := 1+-9+8/-11*(-7)+1*-2*2/5); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := 8*-11*(-7)+1*-2*2/5+9); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := -1); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', r1.f; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abus'); +END r_types; +/ +select adsrc from PG_ATTRDEF where adrelid in (select typrelid from PG_TYPE where typname ilike '%r_type_1%' limit 1); + +DECLARE + r1 r_types.r_type_1; +BEGIN + raise info 'r1.f is %', NVL(r1.f,'NULL'); +END; +/ + +-- test expr error +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (1+)); +END r_types; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := +); +END r_types; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (+)); +END r_types; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f int := (a+b)); +END r_types; +/ + +-- normal default +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abcde', f2 VARCHAR2(5) := 'waxtr'); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f VARCHAR2(5) := 'a1c2e', f2 VARCHAR2(5) := 'w5x3r'); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', NVL(r1.f,'NULL'); + raise info 'r1.f2 is %', NVL(r1.f2,'NULL'); + raise info 'r2.f is %', NVL(r2.f,'NULL'); + raise info 'r1.f2 is %', NVL(r2.f2,'NULL'); +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f date := '2001-9-28', f2 timestamp := '1957-06-13'); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f date := '2000-7-28', f2 timestamp := '1987-06-03'); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f boolean := true, f2 numeric := 19.578); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f boolean := false, f2 numeric := 13.278); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f money := 10.5, f2 int := 15); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f money := 9.6, f2 int := 13); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f integer := 10, f2 oid := 15); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f integer := 9, f2 oid := 13); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', r1.f; + raise info 'r1.f2 is %', r1.f2; + raise info 'r1.f is %', r2.f; + raise info 'r1.f2 is %', r2.f2; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f name := 'abcde', f2 text := 'waxtr'); +END r_types; +/ +DECLARE + TYPE r_type_2 IS RECORD (f name := 'a1c2e', f2 text := 'w5x3r'); + r1 r_types.r_type_1; + r2 r_type_2; +BEGIN + raise info 'r1.f is %', NVL(r1.f,'NULL'); + raise info 'r1.f2 is %', NVL(r1.f2,'NULL'); + raise info 'r2.f is %', NVL(r2.f,'NULL'); + raise info 'r1.f2 is %', NVL(r2.f2,'NULL'); +END; +/ + +-- pkg param default +CREATE OR REPLACE PACKAGE r_types IS + TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abcde', f2 VARCHAR2(5) := 'syutw'); + TYPE r_type_2 IS RECORD (f VARCHAR2(5)); +END r_types; +/ + +CREATE OR REPLACE PROCEDURE p1 ( + x OUT r_types.r_type_1, + y OUT r_types.r_type_2, + z OUT VARCHAR2) +AUTHID CURRENT_USER IS +BEGIN + raise info 'x.f is %', NVL(x.f,'NULL'); + raise info 'x.f2 is %', NVL(x.f2,'NULL'); + raise info 'y.f is %', NVL(y.f,'NULL'); + raise info 'z is %', NVL(z,'NULL'); +END; +/ + +CREATE OR REPLACE PROCEDURE p2 ( + x IN r_types.r_type_1, + y IN r_types.r_type_2, + z IN VARCHAR2) +AUTHID CURRENT_USER IS +BEGIN + raise info 'x.f is %', NVL(x.f,'NULL'); + raise info 'x.f2 is %', NVL(x.f2,'NULL'); + raise info 'y.f is %', NVL(y.f,'NULL'); + raise info 'z is %', NVL(z,'NULL'); +END; +/ + +CREATE OR REPLACE PROCEDURE p3 ( + x INOUT r_types.r_type_1, + y INOUT r_types.r_type_2, + z INOUT VARCHAR2) +AUTHID CURRENT_USER IS +BEGIN + raise info 'x.f is %', NVL(x.f,'NULL'); + raise info 'x.f2 is %', NVL(x.f2,'NULL'); + raise info 'y.f is %', NVL(y.f,'NULL'); + raise info 'z is %', NVL(z,'NULL'); +END; +/ +DECLARE + r1 r_types.r_type_1; + r2 r_types.r_type_2; + s VARCHAR2(5) := 'fghij'; +BEGIN + raise info '===============p1==================='; + p1 (r1, r2, s); + raise info '===============p2==================='; + p2 (r1, r2, s); + raise info '===============p3==================='; + p3 (r1, r2, s); + r1.f:='waqrt'; + r1.f2:='bfgrf'; + r2.f:='nuytg'; + raise info '===============p1==================='; + p1 (r1, r2, s); + raise info '===============p2==================='; + p2 (r1, r2, s); + raise info '===============p3==================='; + p3 (r1, r2, s); +END; +/ + +DROP FUNCTION func1; +DROP FUNCTION func2; +DROP FUNCTION func3; +DROP FUNCTION func4; +DROP PACKAGE r_types; +DROP SCHEMA test_pkg_default_value; \ No newline at end of file