diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index c07dd9ae9..ea1daac54 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -134,6 +134,7 @@ connection_alarm_rate|real|0,1|NULL|NULL| constraint_exclusion|enum|partition,on,off,true,false,yes,no,1,0|NULL|NULL| enable_union_all_subquery_orderby|bool|0,0|NULL|NULL| enable_ignore_case_in_dquotes|bool|0,0|NULL|NULL| +enable_pltype_name_check|bool|0,0|NULL|NULL| instr_unique_sql_track_type|enum|all,top|NULL|NULL| transform_to_numeric_operators|bool|0,0|NULL|NULL| convert_string_to_digit|bool|0,0|NULL|Please don't modify this parameter which will change the type conversion rule and may lead to unpredictable behavior!| diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index cf4f2fb7d..9dd27968c 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -1782,6 +1782,17 @@ static void InitSqlConfigureNamesBool() check_enable_ignore_case_in_dquotes, NULL, NULL}, + {{"enable_pltype_name_check", + PGC_USERSET, + NODE_ALL, + QUERY_TUNING_METHOD, + gettext_noop("Enable PL type check, if the types are different, throw an error."), + NULL}, + &u_sess->attr.attr_sql.enable_pltype_name_check, + false, + NULL, + NULL, + NULL}, {{"enable_streaming", PGC_POSTMASTER, NODE_DISTRIBUTE, diff --git a/src/common/backend/utils/misc/postgresql_single.conf.sample b/src/common/backend/utils/misc/postgresql_single.conf.sample index e78ca1653..358cc1a87 100644 --- a/src/common/backend/utils/misc/postgresql_single.conf.sample +++ b/src/common/backend/utils/misc/postgresql_single.conf.sample @@ -828,7 +828,7 @@ job_queue_processes = 10 # Number of concurrent jobs, optional: [0..1000] #enable_seqscan_fusion = off #enable_cachedplan_mgr=on #enable_ignore_case_in_dquotes=off - +#enable_pltype_name_check=off #------------------------------------------------------------------------------ # SHARED STORAGE OPTIONS #------------------------------------------------------------------------------ diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index bc5f4667b..61b08aea5 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -54,7 +54,7 @@ #include - +#define MAX_LAYER 256 #define LENGTH_OF_BRACKETS_AND_DOT 4 #define LENGTH_OF_QUOTATION_MARKS 2 #define IS_ANONYMOUS_BLOCK \ @@ -228,6 +228,8 @@ static char* get_attrname(int tok); static AttrNumber get_assign_attrno(PLpgSQL_datum* target, char* attrname); static void raw_parse_package_function(char* proc_str, int location, int leaderlen); static void checkFuncName(List* funcname); +static void checkTypeName(List* nest_typnames, List* target_typnames); +static List* get_current_type_nest_type(List* old_nest_typenames, char* typname, bool add_current_type); static void IsInPublicNamespace(char* varname); static void CheckDuplicateCondition (char* name); static void SetErrorState(); @@ -1222,6 +1224,7 @@ as_is : K_IS decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_notnull decl_defval { ListCell *lc = NULL; + PLpgSQL_row* row = NULL; if ((list_length($1) > 1) && ($3 && $3->typoid == REFCURSOROID)) ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -1283,6 +1286,14 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no var = plpgsql_build_variable(varname->name, varname->lineno, $3, true); + if (var->dtype == PLPGSQL_DTYPE_ROW || var->dtype == PLPGSQL_DTYPE_RECORD) + { + row = (PLpgSQL_row*)var; + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + ntype->index = 1; + List* nest_typnames = NIL; + row->nest_typnames = search_external_nest_type($3->typname, $3->typoid, -1, nest_typnames, ntype); + } if ($2) { if (var->dtype == PLPGSQL_DTYPE_VAR) @@ -1315,8 +1326,10 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no ((PLpgSQL_var *) var)->default_val = $6; else if (var->dtype == PLPGSQL_DTYPE_ROW || var->dtype == PLPGSQL_DTYPE_RECORD) { PLpgSQL_row * row = (PLpgSQL_row *) var; - if (!(row->atomically_null_object && pg_strcasecmp($6->query, "select null") == 0)) + if (!(row->atomically_null_object && pg_strcasecmp($6->query, "select null") == 0)) { row->default_val = $6; + checkTypeName($6->nest_typnames, row->nest_typnames); + } } else if (var->dtype == PLPGSQL_DTYPE_CURSORROW) { ((PLpgSQL_rec *) var)->default_val = $6; } @@ -1477,7 +1490,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no u_sess->plsql_cxt.have_error = true; } - plpgsql_build_varrayType($2->name, $2->lineno, $9, true); + PLpgSQL_var* var = (PLpgSQL_var*)plpgsql_build_varrayType($2->name, $2->lineno, $9, true); + var->nest_typnames = get_current_type_nest_type(var->nest_typnames, var->refname, true); if (IS_PACKAGE) { plpgsql_build_package_array_type($2->name, $9->typoid, TYPCATEGORY_ARRAY, $9->dependExtend); } else if (enable_plpgsql_gsdependency()) { @@ -1514,11 +1528,12 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no newp = build_type_from_record_var($9, @9); newp->collectionType = PLPGSQL_COLLECTION_ARRAY; newp->tableOfIndexType = InvalidOid; - plpgsql_build_varrayType($2->name, $2->lineno, newp, true); + PLpgSQL_var* var = (PLpgSQL_var*)plpgsql_build_varrayType($2->name, $2->lineno, newp, true); + PLpgSQL_rec_type* rec_var = (PLpgSQL_rec_type*)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$9]; + var->nest_typnames = get_current_type_nest_type(rec_var->nest_typnames, var->refname, 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]); @@ -1540,6 +1555,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no PLpgSQL_var* var = (PLpgSQL_var*)plpgsql_build_varrayType($2->name, $2->lineno, nest_type, true); /* nested table type */ var->nest_table = (PLpgSQL_var *)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$9]; + List *old_nest_typenames = var->nest_table && var->nest_table->nest_typnames ? var->nest_table->nest_typnames : NULL; + var->nest_typnames = get_current_type_nest_type(old_nest_typenames, var->refname, true); var->nest_layers = depth; var->isIndexByTblOf = false; pfree_ext($2->name); @@ -1581,17 +1598,19 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no PLpgSQL_type *var_type = ((PLpgSQL_var *)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$3])->datatype; PLpgSQL_var *varray_type = (PLpgSQL_var *)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$3]; - PLpgSQL_var *newp; PLpgSQL_type *new_var_type; new_var_type = build_array_type_from_elemtype(var_type); new_var_type->collectionType = var_type->collectionType; new_var_type->tableOfIndexType = var_type->tableOfIndexType; - newp = (PLpgSQL_var *)plpgsql_build_variable(varname->name, varname->lineno, new_var_type, true); newp->isconst = $2; newp->default_val = $4; + newp->nest_typnames = varray_type->nest_typnames; + if (newp->default_val != NULL) { + checkTypeName(newp->default_val->nest_typnames, varray_type->nest_typnames); + } if (NULL == newp) { const char* message = "build variable failed"; @@ -1651,7 +1670,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no erraction("check define of table type"))); u_sess->plsql_cxt.have_error = true; } - plpgsql_build_tableType($2->name, $2->lineno, $6, true); + PLpgSQL_var* var = (PLpgSQL_var*)plpgsql_build_tableType($2->name, $2->lineno, $6, true); + var->nest_typnames = get_current_type_nest_type(var->nest_typnames, var->refname, true); if (IS_PACKAGE) { plpgsql_build_package_array_type($2->name, $6->typoid, TYPCATEGORY_TABLEOF, $6->dependExtend); } else if (enable_plpgsql_gsdependency()) { @@ -1672,6 +1692,8 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no PLpgSQL_var* var = (PLpgSQL_var*)plpgsql_build_tableType($2->name, $2->lineno, nest_type, true); /* nested table type */ var->nest_table = (PLpgSQL_var *)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$6]; + List *old_nest_typenames = var->nest_table && var->nest_table->nest_typnames ? var->nest_table->nest_typnames : NULL; + var->nest_typnames = get_current_type_nest_type(old_nest_typenames, var->refname, true); var->nest_layers = depth; var->isIndexByTblOf = false; pfree_ext($2->name); @@ -1715,11 +1737,12 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no newp = build_type_from_record_var($6, @6); newp->collectionType = PLPGSQL_COLLECTION_TABLE; newp->tableOfIndexType = InvalidOid; - plpgsql_build_tableType($2->name, $2->lineno, newp, true); + PLpgSQL_var* var = (PLpgSQL_var*)plpgsql_build_tableType($2->name, $2->lineno, newp, true); + PLpgSQL_rec_type* rec_var = (PLpgSQL_rec_type*)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$6]; + var->nest_typnames = get_current_type_nest_type(rec_var->nest_typnames, var->refname, 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]); @@ -1962,7 +1985,10 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no } newp->isconst = $2; newp->default_val = $4; - + newp->nest_typnames = table_type->nest_typnames; + if (newp->default_val != NULL) { + checkTypeName(newp->default_val->nest_typnames, table_type->nest_typnames); + } if (table_type->nest_table != NULL) { newp->nest_table = plpgsql_build_nested_variable(table_type->nest_table, $2, varname->name, varname->lineno); newp->nest_layers = table_type->nest_layers; @@ -1977,6 +2003,13 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no PLpgSQL_rec_type *newp = NULL; newp = plpgsql_build_rec_type($2->name, $2->lineno, $6, true); + + PLpgSQL_nest_type *new_ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + new_ntype->typname = pstrdup(newp->typname); + new_ntype->layer = 0; + new_ntype->index = 1; + newp->nest_typnames = lappend(newp->nest_typnames, new_ntype); + if (NULL == newp) { const char* message = "build variable failed"; InsertErrorMessage(message, plpgsql_yylloc); @@ -2018,7 +2051,9 @@ decl_statement : decl_varname_list decl_const decl_datatype decl_collate decl_no u_sess->plsql_cxt.have_error = true; } if ($3 != NULL) { - ((PLpgSQL_row *) newp)->default_val = $3; + PLpgSQL_row* row = (PLpgSQL_row*)newp; + row->default_val = $3; + checkTypeName($3->nest_typnames, row->nest_typnames); } pfree_ext(varname->name); } @@ -2220,10 +2255,18 @@ opt_subtype_range : record_attr_list : record_attr { $$ = list_make1($1); + if ($1->cur_ntype) { + $1->cur_ntype->index = $$->length; + $1->nest_typnames = lappend($1->nest_typnames, $1->cur_ntype); + } } | record_attr_list ',' record_attr { $$ = lappend($1, $3); + if ($3->cur_ntype) { + $3->cur_ntype->index = $$->length; + $3->nest_typnames = lappend($3->nest_typnames, $3->cur_ntype); + } } ; @@ -2247,6 +2290,10 @@ record_attr : attr_name decl_datatype decl_notnull decl_rec_defval attr->type = $2; attr->notnull = $3; + attr->cur_ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + attr->cur_ntype->index = -1; + List* nest_typnames = NIL; + attr->nest_typnames = search_external_nest_type(attr->type->typname, attr->type->typoid, 0, nest_typnames, attr->cur_ntype); if ($4 != NULL) { if (attr->type->ttype == PLPGSQL_TTYPE_SCALAR) @@ -2301,7 +2348,14 @@ record_attr : attr_name decl_datatype decl_notnull decl_rec_defval attr->attrname = $1; attr->type = build_type_from_record_var($2, @2); - + PLpgSQL_rec_type *var_type = (PLpgSQL_rec_type *)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[$2]; + attr->cur_ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + attr->cur_ntype->typname = pstrdup(var_type->typname); + attr->cur_ntype->layer = 1; + if (var_type->nest_typnames != NIL) { + attr->nest_typnames = get_current_type_nest_type(var_type->nest_typnames, NULL, false); + } + attr->notnull = $3; if ($4 != NULL) { @@ -2360,6 +2414,13 @@ record_attr : attr_name decl_datatype decl_notnull decl_rec_defval new_var_type->tableOfIndexType = var_type->tableOfIndexType; attr->type = new_var_type; attr->notnull = $3; + attr->cur_ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + attr->cur_ntype->typname = pstrdup(varray_type->refname); + attr->cur_ntype->layer = 1; + if (varray_type->nest_typnames != NIL) { + attr->nest_typnames = get_current_type_nest_type(varray_type->nest_typnames, NULL, false); + } + if ($4 != NULL) { if (attr->type->ttype == PLPGSQL_TTYPE_SCALAR) @@ -2406,6 +2467,13 @@ record_attr : attr_name decl_datatype decl_notnull decl_rec_defval new_var_type->tableOfIndexType = var_type->tableOfIndexType; attr->type = new_var_type; attr->notnull = $3; + attr->cur_ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + attr->cur_ntype->typname = pstrdup(table_type->refname); + attr->cur_ntype->layer = 1; + if (table_type->nest_typnames != NIL) { + attr->nest_typnames = get_current_type_nest_type(table_type->nest_typnames, NULL, false); + } + if ($4 != NULL) { if (attr->type->ttype == PLPGSQL_TTYPE_SCALAR) @@ -2970,6 +3038,16 @@ stmt_assign : assign_var assign_operator expr_until_semi newp->varno = $1; newp->expr = $3; newp->sqlString = plpgsql_get_curline_query(); + if (newp->expr) { + PLpgSQL_var* target = (PLpgSQL_var*)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[newp->varno]; + List* nest_typnames = NIL; + if (target->dtype == PLPGSQL_DTYPE_RECORD || target->dtype == PLPGSQL_DTYPE_ROW) { + nest_typnames = ((PLpgSQL_row*)target)->nest_typnames; + } else if (target->dtype == PLPGSQL_DTYPE_VAR) { + nest_typnames = target->nest_typnames; + } + checkTypeName(newp->expr->nest_typnames, nest_typnames); + } $$ = (PLpgSQL_stmt *)newp; } @@ -8629,6 +8707,92 @@ static bool oid_is_function(Oid funcid, bool* isSystemObj) return false; } +static void checkTypeName(List* nest_typnames, List* target_nest_typnames) +{ + if (!u_sess->attr.attr_sql.enable_pltype_name_check || + nest_typnames == NIL || target_nest_typnames == NIL) + return; + + ListCell* lc = NULL; + int i = 0; + foreach (lc, nest_typnames) { + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)lfirst(lc); + ListCell* target_typnames = target_nest_typnames->head; + PLpgSQL_nest_type* target_ntype = (PLpgSQL_nest_type*)lfirst(target_typnames); + char* functypname = NULL; + char* pkgtypname = NULL; + List* found_list = NIL; + bool found = false; + + for (i = 0; i < target_nest_typnames->length; i++) { + if (target_ntype->layer == ntype->layer && + (target_ntype->index == -1 || target_ntype->index == ntype->index)) { + found_list = lappend(found_list, target_ntype); + } + if (target_typnames) { + target_typnames = target_typnames->next; + if (target_typnames) { + target_ntype = (PLpgSQL_nest_type*)lfirst(target_typnames); + } + } + } + if (strchr(ntype->typname, '.') == NULL) { + getPkgFuncTypeName(ntype->typname, &functypname, &pkgtypname); + } + if (found_list != NIL) { + ListCell* lcf = NULL; + foreach(lcf, found_list) { + target_ntype = (PLpgSQL_nest_type*)lfirst(lcf); + bool is_row = strcasecmp(ntype->typname, "ROW") == 0; + bool is_equal = strcmp(ntype->typname, target_ntype->typname) == 0; + bool func_name_equal = functypname ? strcmp(functypname, target_ntype->typname) == 0 : false; + bool pkg_name_equal = pkgtypname ? strcmp(pkgtypname, target_ntype->typname) == 0 : false; + + if (is_row || is_equal || func_name_equal || pkg_name_equal) { + found = true; + } + } + } + if (!found) { + char *mes = NULL; + char *report_mes = "Wrong type of expression, should not use type "; + int length = strlen(ntype->typname) + strlen(report_mes) + 3; + mes = (char*)palloc0(length); + errno_t rc = snprintf_s(mes, length, length -1, "%s\"%s\"", report_mes, ntype->typname); + securec_check_ss(rc, "", ""); + InsertErrorMessage(mes, plpgsql_yylloc); + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg(mes))); + } + } +} + +static List* get_current_type_nest_type(List* old_nest_typenames, char* typname, bool add_current_type) +{ + List* nest_typnames = NIL; + ListCell* lc = NULL; + if (old_nest_typenames != NIL) { + int i = 0; + PLpgSQL_nest_type *new_ntypes = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type) * old_nest_typenames->length); + foreach (lc, old_nest_typenames) { + PLpgSQL_nest_type *old_ntype = (PLpgSQL_nest_type *)lfirst(lc); + PLpgSQL_nest_type *new_ntype = new_ntypes + i; + new_ntype->typname = pstrdup(old_ntype->typname); + new_ntype->layer = old_ntype->layer + 1; + new_ntype->index = old_ntype->index; + nest_typnames = lappend(nest_typnames, new_ntype); + i++; + } + } + if (add_current_type) { + PLpgSQL_nest_type *ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(typname); + ntype->layer = 0; + ntype->index = -1; + nest_typnames = lappend(nest_typnames, ntype); + } + return nest_typnames; +} + /* * @brief is_datatype * check if a given type is a datatype @@ -8997,6 +9161,9 @@ read_sql_construct6(int until, bool ds_changed = false; ArrayParseContext context; List *idents = 0; + List* nest_typnames = NIL; + int comma_cnt = 0; + int typname_indexs[MAX_LAYER] = {0}; const char left_bracket[2] = "["; const char right_bracket[2] = "]"; const char left_parentheses[2] = "("; @@ -9009,7 +9176,7 @@ read_sql_construct6(int until, int right_brace_count = 0; bool stop_count = false; int stop_tok; - /* mark if there are 2 table of index by var call functions in an expr */ + /* mark if there are 2 table of index by var call functions in an expr */ int tableof_func_dno = -1; int tableof_var_dno = -1; bool is_have_tableof_index_var = false; @@ -9037,6 +9204,10 @@ read_sql_construct6(int until, { prev_tok = tok; tok = yylex(); + if (tok == ',' && (left_brace_count - right_brace_count) > 0 && + (left_brace_count - right_brace_count) < MAX_LAYER) { + typname_indexs[left_brace_count - right_brace_count] = typname_indexs[left_brace_count - right_brace_count] + 1; + } if (tok == '\"' || tok == '\'') { if (stop_count && stop_tok == tok) { stop_count = false; @@ -9617,6 +9788,11 @@ read_sql_construct6(int until, { nest_layers = var->nest_layers; } + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(var->refname); + ntype->layer = left_brace_count - right_brace_count; + ntype->index = typname_indexs[ntype->layer] + 1; + nest_typnames = lappend(nest_typnames, ntype); ds_changed = construct_array_start(&ds, &context, var->datatype, &tok, parenlevel, loc); break; } @@ -9642,9 +9818,25 @@ read_sql_construct6(int until, { nest_layers = var->nest_layers; } + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(var->refname); + ntype->layer = left_brace_count - right_brace_count; + ntype->index = typname_indexs[ntype->layer] + 1; + nest_typnames = lappend(nest_typnames, ntype); ds_changed = construct_array_start(&ds, &context, var->datatype, &tok, parenlevel, loc); break; } + case T_RECORD: + { + int dno = yylval.wdatum.datum->dno; + PLpgSQL_rec_type* rec_type = (PLpgSQL_rec_type *)u_sess->plsql_cxt.curr_compile_context->plpgsql_Datums[dno]; + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(rec_type->typname); + ntype->layer = left_brace_count - right_brace_count; + ntype->index = typname_indexs[ntype->layer] + 1; + nest_typnames = lappend(nest_typnames, ntype); + break; + } case T_DATUM: { idents = yylval.wdatum.idents; @@ -9669,12 +9861,64 @@ read_sql_construct6(int until, } } case T_WORD: + { + char *name = yylval.word.ident; + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(name); + ntype->layer = left_brace_count - right_brace_count; + ntype->index = typname_indexs[ntype->layer] + 1; + nest_typnames = lappend(nest_typnames, ntype); AddNamespaceIfPkgVar(yylval.word.ident, save_IdentifierLookup); ds_changed = construct_word(&ds, &context, &tok, parenlevel, loc); break; + } case T_CWORD: + { + List* name_list = yylval.cword.idents; + switch(name_list->length) { + case 2: + { + char* packageName = strVal(linitial(name_list)); + char* typeName = strVal(lsecond(name_list)); + Oid namespaceOid = getCurrentNamespace(); + Oid pkgOid = packageName ? PackageNameGetOid(packageName, namespaceOid) : InvalidOid; + if (pkgOid != InvalidOid && namespaceOid != InvalidOid) { + Oid type_oid = LookupTypeInPackage(name_list, typeName, pkgOid, namespaceOid); + if (type_oid != InvalidOid) { + char* castTypeName = CastPackageTypeName(typeName, pkgOid, pkgOid != InvalidOid, true); + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(castTypeName); + ntype->layer = left_brace_count - right_brace_count; + ntype->index = typname_indexs[ntype->layer] + 1; + nest_typnames = lappend(nest_typnames, ntype); + } + } + break; + } + case 3: + { + char* namesapceName = strVal(linitial(name_list)); + char* packageName = strVal(lsecond(name_list)); + char* typeName = strVal(lthird(name_list)); + Oid namespaceOid = namesapceName ? get_namespace_oid(namesapceName, true) : InvalidOid; + Oid pkgOid = packageName ? PackageNameGetOid(packageName, namespaceOid) : InvalidOid; + if (pkgOid != InvalidOid && namespaceOid != InvalidOid) { + Oid type_oid = LookupTypeInPackage(name_list, typeName, pkgOid, namespaceOid); + if (type_oid != InvalidOid) { + char* castTypeName = CastPackageTypeName(typeName, pkgOid, pkgOid != InvalidOid, true); + PLpgSQL_nest_type* ntype = (PLpgSQL_nest_type*)palloc(sizeof(PLpgSQL_nest_type)); + ntype->typname = pstrdup(castTypeName); + ntype->layer = left_brace_count - right_brace_count; + ntype->index = typname_indexs[ntype->layer] + 1; + nest_typnames = lappend(nest_typnames, ntype); + } + } + break; + } + } ds_changed = construct_cword(&ds, &context, &tok, parenlevel, loc); break; + } case T_OBJECT_TYPE_VAR_METHOD: { appendStringInfo(&ds, " %s(", yylval.wdatum.ident); @@ -9810,6 +10054,7 @@ read_sql_construct6(int until, expr->tableof_var_dno = tableof_var_dno; expr->is_have_tableof_index_func = tableof_func_dno != -1 ? true : false; expr->tableof_func_dno = tableof_func_dno; + expr->nest_typnames = nest_typnames ? nest_typnames : NIL; pfree_ext(ds.data); @@ -15158,4 +15403,4 @@ yylex_object_type_selfparam(char ** fieldnames, varnos[nfields] = -1; } pfree_ext(ds.data); -} \ No newline at end of file +} diff --git a/src/common/pl/plpgsql/src/pl_comp.cpp b/src/common/pl/plpgsql/src/pl_comp.cpp index 85fc03f31..d7bf0bd09 100644 --- a/src/common/pl/plpgsql/src/pl_comp.cpp +++ b/src/common/pl/plpgsql/src/pl_comp.cpp @@ -49,6 +49,7 @@ #include "utils/rel.h" #include "utils/rel_gs.h" #include "utils/syscache.h" +#include "utils/typcache.h" #include "miscadmin.h" #include "tcop/tcopprot.h" #include "commands/event_trigger.h" @@ -4222,6 +4223,7 @@ PLpgSQL_rec_type* plpgsql_build_rec_type(const char* typname, int lineno, List* ListCell* cell = NULL; PLpgSQL_rec_attr* attr = NULL; PLpgSQL_rec_type* result = NULL; + List* nest_typnames = NIL; result = (PLpgSQL_rec_type*)palloc0(sizeof(PLpgSQL_rec_type)); @@ -4241,10 +4243,12 @@ PLpgSQL_rec_type* plpgsql_build_rec_type(const char* typname, int lineno, List* result->attrnames[idx] = pstrdup(attr->attrname); result->types[idx] = attr->type; + nest_typnames = lappend3(nest_typnames, attr->nest_typnames); result->notnulls[idx] = attr->notnull; result->defaultvalues[idx] = attr->defaultvalue; idx++; } + result->nest_typnames = nest_typnames; varno = plpgsql_adddatum((PLpgSQL_datum*)result); @@ -4254,6 +4258,38 @@ PLpgSQL_rec_type* plpgsql_build_rec_type(const char* typname, int lineno, List* return result; } +List* search_external_nest_type(char* name, Oid typeOid, int layer, List* nest_typnames, PLpgSQL_nest_type* cur_ntype) +{ + HeapTuple tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid)); + PLpgSQL_nest_type* nntype = NULL; + int typmod = -1; + int natts = 1; + layer++; + if (tuple) { + cur_ntype->typname = pstrdup(name); + cur_ntype->layer = layer; + if (cur_ntype->index != -1) { + nest_typnames = lappend(nest_typnames, cur_ntype); + } + TupleDesc tuple_desc = lookup_rowtype_tupdesc_noerror(typeOid, typmod, true); + if (tuple_desc) { + natts = tuple_desc->natts; + for (int i = 0; i < natts; i++) { + Form_pg_attribute attr = TupleDescAttr(tuple_desc, i); + if (!attr->attisdropped && attr->atttypid != InvalidOid) { + char* typname = get_typename(attr->atttypid); + PLpgSQL_nest_type* new_ntype = (PLpgSQL_nest_type *)palloc(sizeof(PLpgSQL_nest_type)); + new_ntype->index = i + 1; + nest_typnames = search_external_nest_type(typname, attr->atttypid, layer, nest_typnames, new_ntype); + } + } + ReleaseTupleDesc(tuple_desc); + } + ReleaseSysCache(tuple); + } + return nest_typnames; +} + /* * typname: SUBTYPE name * basetypname: base type name @@ -4557,6 +4593,7 @@ PLpgSQL_row* build_row_from_rec_type(const char* rowname, int lineno, PLpgSQL_re row->default_val = NULL; row->recordVarTypOid = type->typoid; row->atomically_null_object = false; + row->nest_typnames = type->nest_typnames; for (int i = 0; i < row->nfields; i++) { PLpgSQL_variable* var = NULL; diff --git a/src/include/knl/knl_guc/knl_session_attr_sql.h b/src/include/knl/knl_guc/knl_session_attr_sql.h index 414ea8c70..5b26d130a 100644 --- a/src/include/knl/knl_guc/knl_session_attr_sql.h +++ b/src/include/knl/knl_guc/knl_session_attr_sql.h @@ -251,6 +251,7 @@ typedef struct knl_session_attr_sql { char* db4ai_snapshot_version_delimiter; char* db4ai_snapshot_version_separator; bool enable_ignore_case_in_dquotes; + bool enable_pltype_name_check; int pldebugger_timeout; bool partition_page_estimation; bool enable_opfusion_reuse; diff --git a/src/include/utils/plpgsql.h b/src/include/utils/plpgsql.h index 3d14b6e75..ecadc93ed 100644 --- a/src/include/utils/plpgsql.h +++ b/src/include/utils/plpgsql.h @@ -323,6 +323,11 @@ typedef enum { /********************************************************************** * Node and structure definitions **********************************************************************/ +typedef struct PLpgSQL_nest_type { /* Generic datum array item */ + char* typname; + int layer; + int index; +} PLpgSQL_nest_type; /* * PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var, * PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem @@ -400,6 +405,7 @@ typedef struct PLpgSQL_expr { /* SQpL Query to plan and execute */ int dno; bool ispkg; char* query; + List* nest_typnames; SPIPlanPtr plan; Bitmapset* paramnos; /* all dnos referenced by this query */ @@ -530,6 +536,7 @@ typedef struct PLpgSQL_var { /* Scalar variable */ struct PLpgSQL_var* nest_table; /* origin nest table type, copy from it when add new nest table */ HTAB* tableOfIndex = NULL; /* mapping of table of index */ int nest_layers = 0; + List* nest_typnames; } PLpgSQL_var; typedef struct { /* Row variable */ @@ -566,6 +573,7 @@ typedef struct { /* Row variable */ Oid recordVarTypOid; /* package record var's composite type oid */ bool hasExceptionInit; bool atomically_null_object; + List* nest_typnames; } PLpgSQL_row; typedef struct { @@ -573,6 +581,8 @@ typedef struct { PLpgSQL_type* type; bool notnull; PLpgSQL_expr* defaultvalue; + List* nest_typnames; + PLpgSQL_nest_type* cur_ntype; } PLpgSQL_rec_attr; typedef struct { @@ -595,6 +605,7 @@ typedef struct { bool* notnulls; bool addNamespace; PLpgSQL_expr** defaultvalues; + List* nest_typnames; } PLpgSQL_rec_type; typedef struct { /* Record variable (non-fixed structure) */ @@ -1825,6 +1836,8 @@ extern PLpgSQL_variable* plpgsql_build_variable(const char* refname, int lineno, PLpgSQL_variable* plpgsql_build_varrayType(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace); PLpgSQL_variable* plpgsql_build_tableType(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace); extern PLpgSQL_rec_type* plpgsql_build_rec_type(const char* typname, int lineno, List* list, bool add2namespace); +extern List* search_external_nest_type(char* name, Oid typeOid, + int layer, List* nest_typnames, PLpgSQL_nest_type* cur_ntype); extern PLpgSQL_rec* plpgsql_build_record(const char* refname, int lineno, bool add2namespace, TupleDesc tupleDesc); extern void plpgsql_build_synonym(char* typname, char* basetypname); extern int plpgsql_recognize_err_condition(const char* condname, bool allow_sqlstate); diff --git a/src/test/regress/expected/plpgsql_assign_list.out b/src/test/regress/expected/plpgsql_assign_list.out index 183b8ea96..4d240e2d2 100644 --- a/src/test/regress/expected/plpgsql_assign_list.out +++ b/src/test/regress/expected/plpgsql_assign_list.out @@ -236,6 +236,776 @@ CONTEXT: referenced column: get_age 456 (1 row) +--test assign a value to a variable with a custom type +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec:= t_rec2(1, ',', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ +INFO: team.LIMIT = , +set enable_pltype_name_check = on; +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec:= t_rec(1, 'ONE', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ +INFO: team.LIMIT = ONE +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec:= t_rec2(1, ',', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 11 +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec:= t_rec2(1, 'ONE', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 11 +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec; +BEGIN + l_rec := t_rec2(1, 'ONE', 'TWO', 'THREE'); +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 13 +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec; +BEGIN + l_rec := t_rec(1, 'ONE', 'TWO', 'THREE'); +END; +/ +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec; +BEGIN + l_rec := ROW(1, 'ONE', 'TWO', 'THREE'); +END; +/ +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec; +BEGIN + l_rec := row(1, 'ONE', 'TWO', 'THREE'); +END; +/ +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + l_rec t_rec; +BEGIN + l_rec := t_rec2(1, 'ONE', 'TWO', 'THREE'); +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 8 +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type; +BEGIN + nt := va_type(1,3,5); + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ +ERROR: Wrong type of expression, should not use type "va_type" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 5 +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type; +BEGIN + nt := nt_type(1,3,5); + raise info 'team.LIMIT = %', nt(2); +END; +/ +INFO: team.LIMIT = 3 +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type:= va_type(1,3,5); +BEGIN + raise info 'nt(3) = %', nt(1); +END; +/ +ERROR: Wrong type of expression, should not use type "va_type" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 3 +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type:= nt_type(1,3,5); +BEGIN + raise info 'nt(3) = %', nt(1); +END; +/ +INFO: nt(3) = 1 +DECLARE + TYPE va_type IS VARRAY(4) OF INTEGER; + nt va_type := va_type(1,3,5); +BEGIN + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ +INFO: nt(1) = 1 +INFO: nt(3) = 5 +DECLARE + TYPE va_type IS VARRAY(4) OF INTEGER; + nt va_type; +BEGIN + nt := va_type(1,3,5); + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ +INFO: nt(1) = 1 +INFO: nt(3) = 5 +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + nt nt_type := nt_type(1,3,5); +BEGIN + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ +INFO: nt(1) = 1 +INFO: nt(3) = 5 +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + nt nt_type; +BEGIN + nt := nt_type(1,3,5); + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ +INFO: nt(1) = 1 +INFO: nt(3) = 5 +--test nest record +create type to1 as (val1 VARCHAR2(10), val2 VARCHAR2(10)); +create type to2 as (val3 VARCHAR2(10), val4 to1); +create type to3 as (val5 VARCHAR2(10), val6 to2, val7 to1); +DECLARE + l_rec to3:= ('ONE', to2('TWO',to2(',', 'FOUR')),to1('FIVE','SIX')); +BEGIN + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "to2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 1 +DECLARE + l_rec to3; +BEGIN + l_rec := ('ONE', to2('TWO',to3(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "to3" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 3 +CREATE OR REPLACE PACKAGE r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val4 t_rec0, val3 VARCHAR2(10)); +END r_types; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 r_types.t_rec1, val7 r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(r_types.t_rec0(',', 'FOUR'), 'TWO'), r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 r_types.t_rec1, val7 r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(r_types.t_rec1(',', 'FOUR'), 'TWO'), r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PACKAGE r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); +END r_types; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec1(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 6 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 6 +DROP PACKAGE r_types; +--?.* +CREATE OR REPLACE PACKAGE plpgsql_assignlist.r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val4 t_rec0, val3 VARCHAR2(10)); +END r_types; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 plpgsql_assignlist.r_types.t_rec1, val7 plpgsql_assignlist.r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(r_types.t_rec0(',', 'FOUR'), 'TWO'),plpgsql_assignlist.r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 plpgsql_assignlist.r_types.t_rec1, val7 r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(plpgsql_assignlist.r_types.t_rec1(',', 'FOUR'), 'TWO'),r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PACKAGE plpgsql_assignlist.r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); +END r_types; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 plpgsql_assignlist.r_types.t_rec1, val7 plpgsql_assignlist.r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),plpgsql_assignlist.r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 plpgsql_assignlist.r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',plpgsql_assignlist.r_types.t_rec1(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 plpgsql_assignlist.r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', plpgsql_assignlist.r_types.t_rec1('TWO',plpgsql_assignlist.r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 plpgsql_assignlist.r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 plpgsql_assignlist.r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', plpgsql_assignlist.r_types.t_rec1('TWO',plpgsql_assignlist.r_types.t_rec0(',', 'FOUR')),plpgsql_assignlist.r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 6 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', t_rec1('TWO',plpgsql_assignlist.r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 plpgsql_assignlist.r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', plpgsql_assignlist.r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +--?.* +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 6 +DROP PACKAGE r_types; +--?.* +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ +ERROR: nested table of type is not supported as record type attribute +LINE 5: TYPE rec1 IS RECORD(id int, arrarg nt1); + ^ +QUERY: DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr1(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ +ERROR: nested table of type is not supported as record type attribute +LINE 5: TYPE rec1 IS RECORD(id int, arrarg nt1); + ^ +QUERY: DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr1(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1; +BEGIN + arr_rec:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))) + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ +ERROR: nested table of type is not supported as record type attribute +LINE 5: TYPE rec1 IS RECORD(id int, arrarg nt1); + ^ +QUERY: DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1; +BEGIN + arr_rec:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))) + RAISE NOTICE 'ID: %', arr_rec.id; +END +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ +ERROR: nested table of type is not supported as record type attribute +LINE 5: TYPE rec1 IS RECORD(id int, arrarg nt1); + ^ +QUERY: DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr1(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ +ERROR: nested table of type is not supported as record type attribute +LINE 5: TYPE rec1 IS RECORD(id int, arrarg nt1); + ^ +QUERY: DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr1(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1; +BEGIN + arr_rec:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))) + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ +ERROR: nested table of type is not supported as record type attribute +LINE 5: TYPE rec1 IS RECORD(id int, arrarg nt1); + ^ +QUERY: DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1; +BEGIN + arr_rec:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))) + RAISE NOTICE 'ID: %', arr_rec.id; +END +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 to1); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to2(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "to2" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 to1); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to1(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 t_rec0); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to1(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "to1" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 7 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 to1); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 t_rec1); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to1(',', 'FOUR')),t_rec2('A', to1('FIVE','SIX'))); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val4.val1; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 7 +DECLARE + l_rec to3; +BEGIN + l_rec := to2('ONE', to2('TWO',to1(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "to2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 3 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 t_rec0); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', t_rec1('TWO',t_rec2(',', 'FOUR')),t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 7 +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 t_rec0); + l_rec t_rec2 := ('ONE', t_rec1(',',t_rec2('THREE', 'FOUR')),t_rec0('FIVE','SIX')); +BEGIN + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ +ERROR: Wrong type of expression, should not use type "t_rec2" +CONTEXT: compilation of PL/pgSQL function "test_nested" near line 5 +--test nest table +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11; +BEGIN + nva := nt11(nt1(t1(4,5,6), t2(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +END; +/ +ERROR: Wrong type of expression, should not use type "t2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 9 +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11; +BEGIN + nva := nt22(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +END; +/ +ERROR: Wrong type of expression, should not use type "nt22" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 9 +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11; +BEGIN + nva := nt11(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt2(t1(2,4),t1(2,8))); +END; +/ +ERROR: Wrong type of expression, should not use type "nt2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 9 +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11 := nt11(nt1(t1(4,5,6), t2(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +va2 t2; +BEGIN + va2(1):=9; +END; +/ +ERROR: Wrong type of expression, should not use type "t2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 7 +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11 := nt22(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +va2 t2; +BEGIN + va2(1):=9; +END; +/ +ERROR: Wrong type of expression, should not use type "nt22" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 7 +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11 := nt11(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt2(t1(2,4),t1(2,8))); +va2 t2; +BEGIN + va2(1):=9; +END; +/ +ERROR: Wrong type of expression, should not use type "nt2" +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 7 +set enable_pltype_name_check = off; --test o1.col1.col2 ref create type ct as (num int,info text); create type ct1 as (num int,info ct); @@ -306,3 +1076,8 @@ drop type if exists o2; drop type if exists o1; -- clean up -- drop schema if exists plpgsql_assignlist cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to type to1 +drop cascades to type to2 +drop cascades to type to3 +drop cascades to function test_nested() diff --git a/src/test/regress/sql/plpgsql_assign_list.sql b/src/test/regress/sql/plpgsql_assign_list.sql index 25520392f..0ed3b7acb 100644 --- a/src/test/regress/sql/plpgsql_assign_list.sql +++ b/src/test/regress/sql/plpgsql_assign_list.sql @@ -158,6 +158,699 @@ end; $$ language plpgsql; select get_age(); +--test assign a value to a variable with a custom type +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec:= t_rec2(1, ',', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ + +set enable_pltype_name_check = on; +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec:= t_rec(1, 'ONE', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec:= t_rec2(1, ',', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec:= t_rec2(1, 'ONE', 'TWO', 'THREE'); +BEGIN + raise info 'team.LIMIT = %', l_rec.val1; +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + TYPE t_rec2 IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec; +BEGIN + l_rec := t_rec2(1, 'ONE', 'TWO', 'THREE'); +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec; +BEGIN + l_rec := t_rec(1, 'ONE', 'TWO', 'THREE'); +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec; +BEGIN + l_rec := ROW(1, 'ONE', 'TWO', 'THREE'); +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec; +BEGIN + l_rec := row(1, 'ONE', 'TWO', 'THREE'); +END; +/ + +DECLARE + TYPE t_rec IS RECORD ( + id NUMBER, + val1 VARCHAR2(10), + val2 VARCHAR2(10), + val3 VARCHAR2(10) ); + + l_rec t_rec; +BEGIN + l_rec := t_rec2(1, 'ONE', 'TWO', 'THREE'); +END; +/ + +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type; +BEGIN + nt := va_type(1,3,5); + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ + +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type; +BEGIN + nt := nt_type(1,3,5); + raise info 'team.LIMIT = %', nt(2); +END; +/ + +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type:= va_type(1,3,5); +BEGIN + raise info 'nt(3) = %', nt(1); +END; +/ + +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + TYPE va_type IS VARRAY(4) OF INTEGER; + nt nt_type:= nt_type(1,3,5); +BEGIN + raise info 'nt(3) = %', nt(1); +END; +/ + +DECLARE + TYPE va_type IS VARRAY(4) OF INTEGER; + nt va_type := va_type(1,3,5); +BEGIN + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ + +DECLARE + TYPE va_type IS VARRAY(4) OF INTEGER; + nt va_type; +BEGIN + nt := va_type(1,3,5); + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ + +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + nt nt_type := nt_type(1,3,5); +BEGIN + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ + +DECLARE + TYPE nt_type IS TABLE OF INTEGER; + nt nt_type; +BEGIN + nt := nt_type(1,3,5); + raise info 'nt(1) = %', nt(1); + raise info 'nt(3) = %', nt(3); +END; +/ + +--test nest record +create type to1 as (val1 VARCHAR2(10), val2 VARCHAR2(10)); +create type to2 as (val3 VARCHAR2(10), val4 to1); +create type to3 as (val5 VARCHAR2(10), val6 to2, val7 to1); + +DECLARE + l_rec to3:= ('ONE', to2('TWO',to2(',', 'FOUR')),to1('FIVE','SIX')); +BEGIN + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +DECLARE + l_rec to3; +BEGIN + l_rec := ('ONE', to2('TWO',to3(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val4 t_rec0, val3 VARCHAR2(10)); +END r_types; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 r_types.t_rec1, val7 r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(r_types.t_rec0(',', 'FOUR'), 'TWO'), r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 r_types.t_rec1, val7 r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(r_types.t_rec1(',', 'FOUR'), 'TWO'), r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PACKAGE r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); +END r_types; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec1(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +DROP PACKAGE r_types; + +CREATE OR REPLACE PACKAGE plpgsql_assignlist.r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val4 t_rec0, val3 VARCHAR2(10)); +END r_types; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 plpgsql_assignlist.r_types.t_rec1, val7 plpgsql_assignlist.r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(r_types.t_rec0(',', 'FOUR'), 'TWO'),plpgsql_assignlist.r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val6 plpgsql_assignlist.r_types.t_rec1, val7 r_types.t_rec0, val5 VARCHAR2(10)); + l_rec t_rec2; +BEGIN + l_rec := t_rec2(r_types.t_rec1(plpgsql_assignlist.r_types.t_rec1(',', 'FOUR'), 'TWO'),r_types.t_rec0('FIVE','SIX'), 'ONE'); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PACKAGE plpgsql_assignlist.r_types IS + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); +END r_types; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 plpgsql_assignlist.r_types.t_rec1, val7 plpgsql_assignlist.r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),plpgsql_assignlist.r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 plpgsql_assignlist.r_types.t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', r_types.t_rec1('TWO',plpgsql_assignlist.r_types.t_rec1(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 r_types.t_rec1, val7 plpgsql_assignlist.r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', plpgsql_assignlist.r_types.t_rec1('TWO',plpgsql_assignlist.r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 plpgsql_assignlist.r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 plpgsql_assignlist.r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', plpgsql_assignlist.r_types.t_rec1('TWO',plpgsql_assignlist.r_types.t_rec0(',', 'FOUR')),plpgsql_assignlist.r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', t_rec1('TWO',plpgsql_assignlist.r_types.t_rec0(',', 'FOUR')),r_types.t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 plpgsql_assignlist.r_types.t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 r_types.t_rec0); + l_rec t_rec2; +BEGIN + l_rec := t_rec2('ONE', plpgsql_assignlist.r_types.t_rec1('TWO',r_types.t_rec0(',', 'FOUR')),t_rec2('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +DROP PACKAGE r_types; + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr1(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS VARRAY(5) OF INTEGER; + TYPE arr1 IS VARRAY(5) OF INTEGER; + TYPE nt1 IS VARRAY(10) OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1; +BEGIN + arr_rec:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))) + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1:=rec1(7, nt1(arr1(1,2,4,5),arr1(1,3))); +BEGIN + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE arr2 IS TABLE OF INTEGER; + TYPE arr1 IS TABLE OF INTEGER; + TYPE nt1 IS TABLE OF arr1; + TYPE rec1 IS RECORD(id int, arrarg nt1); + arr_rec rec1; +BEGIN + arr_rec:=rec1(7, nt1(arr2(1,2,4,5),arr1(1,3))) + RAISE NOTICE 'ID: %', arr_rec.id; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 to1); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to2(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 to1); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to1(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 t_rec0); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to1(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 to1); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 to2, val7 t_rec1); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', to2('TWO',to1(',', 'FOUR')),t_rec2('A', to1('FIVE','SIX'))); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val4.val1; +END; +/ + +DECLARE + l_rec to3; +BEGIN + l_rec := to2('ONE', to2('TWO',to1(',', 'FOUR')),to1('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 t_rec0); + l_rec t_rec2; +BEGIN + l_rec := ('ONE', t_rec1('TWO',t_rec2(',', 'FOUR')),t_rec0('FIVE','SIX')); + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +CREATE OR REPLACE PROCEDURE test_nested AS +DECLARE + TYPE t_rec0 IS RECORD (val1 VARCHAR2(10), val2 VARCHAR2(10)); + TYPE t_rec1 IS RECORD (val3 VARCHAR2(10), val4 t_rec0); + TYPE t_rec2 IS RECORD (val5 VARCHAR2(10), val6 t_rec1, val7 t_rec0); + l_rec t_rec2 := ('ONE', t_rec1(',',t_rec2('THREE', 'FOUR')),t_rec0('FIVE','SIX')); +BEGIN + RAISE NOTICE 'ID: %, NAME: %', l_rec.val5, l_rec.val6.val3; + RAISE NOTICE 'ID: %, NAME: %', l_rec.val6.val4.val1, l_rec.val7.val2; +END; +/ + +--test nest table +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11; +BEGIN + nva := nt11(nt1(t1(4,5,6), t2(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +END; +/ + +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11; +BEGIN + nva := nt22(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +END; +/ + +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11; +BEGIN + nva := nt11(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt2(t1(2,4),t1(2,8))); +END; +/ + +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11 := nt11(nt1(t1(4,5,6), t2(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +va2 t2; +BEGIN + va2(1):=9; +END; +/ + +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11 := nt22(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt1(t1(2,4),t1(2,8))); +va2 t2; +BEGIN + va2(1):=9; +END; +/ + +DECLARE +TYPE t1 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE t2 IS VARRAY(10) OF INTEGER; -- varray of integer +TYPE nt2 IS VARRAY(10) OF t2; -- varray of varray of integer +TYPE nt1 IS VARRAY(10) OF t1; -- varray of varray of integer +TYPE nt22 IS VARRAY(10) OF nt2; -- varray of varray of integer +TYPE nt11 IS VARRAY(10) OF nt1; -- varray of varray of integer +nva nt11 := nt11(nt1(t1(4,5,6), t1(55,6,73), t1(2,4), t1(2,5,6)),nt2(t1(2,4),t1(2,8))); +va2 t2; +BEGIN + va2(1):=9; +END; +/ + +set enable_pltype_name_check = off; + --test o1.col1.col2 ref create type ct as (num int,info text); create type ct1 as (num int,info ct);