diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index b90a9be3f3..2937e148f3 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -136,7 +136,8 @@ Proposed syntax for testing: COMMENT ON DATABASE IS {'txt'|NULL}; COMMENT ON name IS {'txt'|NULL}; COMMENT ON COLUMN table_or_view_name.field_name IS {'txt'|NULL}; -COMMENT ON PARAMETER procedure_name.param_name IS {'txt'|NULL}; +COMMENT ON {PROCEDURE | FUNCTION} [ .] name.param_name IS {'txt'|NULL}; +COMMENT ON [PROCEDURE | FUNCTION] PARAMETER [ .] name.param_name IS {'txt'|NULL}; An empty literal string '' will act as NULL since the internal code (DYN in this case) works this way with blobs. diff --git a/src/common/classes/QualifiedName.h b/src/common/classes/QualifiedName.h index 7fbfc43d4a..6557ad18f1 100644 --- a/src/common/classes/QualifiedName.h +++ b/src/common/classes/QualifiedName.h @@ -47,6 +47,12 @@ public: { } + QualifiedName(MemoryPool& p, const MetaName& aIdentifier) + : identifier(p, aIdentifier), + package(p) + { + } + explicit QualifiedName(const MetaName& aIdentifier) : identifier(aIdentifier) { diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index f1ccfc02f1..db43928418 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1054,7 +1054,7 @@ void CommentOnNode::print(string& text) const " objType: %s\n" " objName: %s\n" " text: %s\n", - objType, objName.c_str(), this->text.c_str()); + objType, objName.toString().c_str(), this->text.c_str()); } bool CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) @@ -1078,54 +1078,52 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const char* subColumnClause = NULL; const char* addWhereClause = NULL; Arg::StatusVector status; + string objNameStr = objName.toString(); if (objType == obj_parameter) { fb_assert(subName.hasData()); - PreparedStatement::Builder sql; - sql << "select 1 from rdb$procedures p join rdb$procedure_parameters pp using (rdb$procedure_name)" << - "where p.rdb$procedure_name =" << objName << - "and p.rdb$package_name is null and pp.rdb$package_name is null" << - "and pp.rdb$parameter_name =" << subName << - "union all" << - "select 2 from rdb$functions f join rdb$function_arguments fa using (rdb$function_name)" << - "where f.rdb$function_name =" << objName << - "and f.rdb$package_name is null and fa.rdb$package_name is null" << - "and fa.rdb$argument_name =" << subName; + AutoRequest requestHandle; - AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql)); - AutoResultSet rs(ps->executeQuery(tdbb, transaction)); + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + FUN IN RDB$FUNCTIONS CROSS + ARG IN RDB$FUNCTION_ARGUMENTS + WITH FUN.RDB$FUNCTION_NAME EQ objName.identifier.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(objName.package.c_str(), '') AND + ARG.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND + ARG.RDB$PACKAGE_NAME EQUIV FUN.RDB$PACKAGE_NAME AND + ARG.RDB$ARGUMENT_NAME EQ subName.c_str() + { + objType = obj_udf; + } + END_FOR - if (!rs->fetch(tdbb)) + requestHandle.reset(); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + PRC IN RDB$PROCEDURES CROSS + PRM IN RDB$PROCEDURE_PARAMETERS + WITH PRC.RDB$PROCEDURE_NAME EQ objName.identifier.c_str() AND + PRC.RDB$PACKAGE_NAME EQUIV NULLIF(objName.package.c_str(), '') AND + PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND + PRM.RDB$PACKAGE_NAME EQUIV PRC.RDB$PACKAGE_NAME AND + PRM.RDB$PARAMETER_NAME EQ subName.c_str() + { + if (objType == obj_parameter) + objType = obj_procedure; + else + { + status_exception::raise(Arg::Gds(isc_dyn_routine_param_ambiguous) << + Arg::Str(subName) << Arg::Str(objNameStr)); + } + } + END_FOR + + if (objType == obj_parameter) { status_exception::raise(Arg::Gds(isc_dyn_routine_param_not_found) << - Arg::Str(subName) << Arg::Str(objName)); - } - - fb_assert(!rs->isNull(1)); - dsc& desc = rs->getDesc(1); - fb_assert(desc.dsc_dtype == dtype_long); - const SLONG result = *reinterpret_cast(desc.dsc_address); - - switch (result) - { - case 1: - objType = obj_procedure; - break; - - case 2: - objType = obj_udf; - break; - - default: - fb_assert(false); - } - - if (rs->fetch(tdbb)) - { - status_exception::raise(Arg::Gds(isc_dyn_routine_param_ambiguous) << - Arg::Str(subName) << Arg::Str(objName)); + Arg::Str(subName) << Arg::Str(objNameStr)); } } @@ -1147,13 +1145,13 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, tableClause = "rdb$relation_fields"; subColumnClause = "rdb$field_name"; status << Arg::Gds(isc_dyn_column_does_not_exist) << - Arg::Str(subName) << Arg::Str(objName); + Arg::Str(subName) << Arg::Str(objNameStr); } else { tableClause = "rdb$relations"; addWhereClause = "rdb$view_blr is null"; - status << Arg::Gds(isc_dyn_table_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_table_not_found) << Arg::Str(objNameStr); } columnClause = "rdb$relation_name"; break; @@ -1161,7 +1159,7 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, case obj_view: tableClause = "rdb$relations"; columnClause = "rdb$relation_name"; - status << Arg::Gds(isc_dyn_view_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_view_not_found) << Arg::Str(objNameStr); addWhereClause = "rdb$view_blr is not null"; break; @@ -1171,22 +1169,21 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, tableClause = "rdb$procedure_parameters"; subColumnClause = "rdb$parameter_name"; status << Arg::Gds(isc_dyn_proc_param_not_found) << - Arg::Str(subName) << Arg::Str(objName); + Arg::Str(subName) << Arg::Str(objNameStr); } else { tableClause = "rdb$procedures"; - status << Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(objNameStr); } - addWhereClause = "rdb$package_name is null"; columnClause = "rdb$procedure_name"; break; case obj_trigger: tableClause = "rdb$triggers"; columnClause = "rdb$trigger_name"; - status << Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_trig_not_found) << Arg::Str(objNameStr); break; case obj_udf: @@ -1195,70 +1192,69 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, tableClause = "rdb$function_arguments"; subColumnClause = "rdb$argument_name"; status << Arg::Gds(isc_dyn_func_param_not_found) << - Arg::Str(subName) << Arg::Str(objName); + Arg::Str(subName) << Arg::Str(objNameStr); } else { tableClause = "rdb$functions"; - status << Arg::Gds(isc_dyn_func_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_func_not_found) << Arg::Str(objNameStr); } - addWhereClause = "rdb$package_name is null"; columnClause = "rdb$function_name"; break; case obj_blob_filter: tableClause = "rdb$filters"; columnClause = "rdb$function_name"; - status << Arg::Gds(isc_dyn_filter_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_filter_not_found) << Arg::Str(objNameStr); break; case obj_exception: tableClause = "rdb$exceptions"; columnClause = "rdb$exception_name"; - status << Arg::Gds(isc_dyn_exception_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_exception_not_found) << Arg::Str(objNameStr); break; case obj_generator: tableClause = "rdb$generators"; columnClause = "rdb$generator_name"; - status << Arg::Gds(isc_dyn_gen_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_gen_not_found) << Arg::Str(objNameStr); break; case obj_index: tableClause = "rdb$indices"; columnClause = "rdb$index_name"; - status << Arg::Gds(isc_dyn_index_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_index_not_found) << Arg::Str(objNameStr); break; case obj_sql_role: tableClause = "rdb$roles"; columnClause = "rdb$role_name"; - status << Arg::Gds(isc_dyn_role_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_role_not_found) << Arg::Str(objNameStr); break; case obj_charset: tableClause = "rdb$character_sets"; columnClause = "rdb$character_set_name"; - status << Arg::Gds(isc_dyn_charset_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_charset_not_found) << Arg::Str(objNameStr); break; case obj_collation: tableClause = "rdb$collations"; columnClause = "rdb$collation_name"; - status << Arg::Gds(isc_dyn_collation_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_collation_not_found) << Arg::Str(objNameStr); break; case obj_package_header: tableClause = "rdb$packages"; columnClause = "rdb$package_name"; - status << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(objNameStr); break; case obj_schema: tableClause = "rdb$schemas"; columnClause = "rdb$schema_name"; - status << Arg::Gds(isc_dyn_schema_not_found) << Arg::Str(objName); + status << Arg::Gds(isc_dyn_schema_not_found) << Arg::Str(objNameStr); break; default: @@ -1271,16 +1267,19 @@ void CommentOnNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, description = text; PreparedStatement::Builder sql; - sql << "update" << tableClause << "set rdb$description =" << description; + sql << "update" << tableClause << "set rdb$description =" << description << "where 1 = 1"; if (columnClause) { - sql << "where" << columnClause << "=" << objName; + sql << "and" << columnClause << "=" << objName.identifier; if (subColumnClause) sql << "and" << subColumnClause << "=" << subName; } + if (objType == obj_procedure || objType == obj_udf) + sql << "and rdb$package_name is not distinct from nullif(" << objName.package << ", '')"; + if (addWhereClause) sql << "and" << addWhereClause; diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 82ec6019d0..b71dfc35c9 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -220,7 +220,7 @@ class CommentOnNode : public DdlNode { public: CommentOnNode(MemoryPool& pool, int aObjType, - const Firebird::MetaName& aObjName, const Firebird::MetaName& aSubName, + const Firebird::QualifiedName& aObjName, const Firebird::MetaName& aSubName, const Firebird::string aText) : DdlNode(pool), objType(aObjType), @@ -238,18 +238,21 @@ public: protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - /*** ASF: FIXME: When returning, str is destroyed but its pointer is recorded. - Firebird::string str(objName.c_str()); + Firebird::string str(objName.toString()); + if (subName.hasData()) str.append(".").append(subName.c_str()); - statusVector << Firebird::Arg::Gds(isc_dsql_comment_on_failed) << str; - ***/ - statusVector << Firebird::Arg::Gds(isc_dsql_comment_on_failed) << objName; + + //// ASF: What a hack, as StatusVector does not save the pointer content! + const char* p = Firebird::MasterInterfacePtr()->circularAlloc(str.c_str(), str.length(), + (intptr_t) getThreadId()); + + statusVector << Firebird::Arg::Gds(isc_dsql_comment_on_failed) << p; } private: int objType; - Firebird::MetaName objName; + Firebird::QualifiedName objName; Firebird::MetaName subName; Firebird::string text; }; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index f9fa81da10..1ad95508e1 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -619,6 +619,7 @@ using namespace Firebird; Firebird::MetaName* metaNamePtr; Firebird::ObjectsArray* metaNameArray; Firebird::PathName* pathNamePtr; + Firebird::QualifiedName* qualifiedNamePtr; Firebird::string* stringPtr; Jrd::IntlString* intlStringPtr; Jrd::DbFileClause* dbFileClause; @@ -4723,11 +4724,15 @@ set_statistics %type comment comment : COMMENT ON ddl_type0 IS ddl_desc - { $$ = newNode($3, "", "", *$5); } + { $$ = newNode($3, QualifiedName(""), "", *$5); } | COMMENT ON ddl_type1 symbol_ddl_name IS ddl_desc - { $$ = newNode($3, *$4, "", *$6); } + { $$ = newNode($3, QualifiedName(*$4), "", *$6); } | COMMENT ON ddl_type2 symbol_ddl_name ddl_subname IS ddl_desc + { $$ = newNode($3, QualifiedName(*$4), *$5, *$7); } + | COMMENT ON ddl_type3 ddl_qualified_name ddl_subname IS ddl_desc { $$ = newNode($3, *$4, *$5, *$7); } + | COMMENT ON ddl_type4 ddl_qualified_name IS ddl_desc + { $$ = newNode($3, *$4, "", *$6); } | COMMENT ON USER symbol_user_name IS ddl_desc { CreateAlterUserNode* node = @@ -4748,10 +4753,7 @@ ddl_type1 : KW_DOMAIN { $$ = obj_field; } | TABLE { $$ = obj_relation; } | VIEW { $$ = obj_view; } - | PROCEDURE { $$ = obj_procedure; } | TRIGGER { $$ = obj_trigger; } - | EXTERNAL FUNCTION { $$ = obj_udf; } - | FUNCTION { $$ = obj_udf; } | FILTER { $$ = obj_blob_filter; } | EXCEPTION { $$ = obj_exception; } | GENERATOR { $$ = obj_generator; } @@ -4769,14 +4771,20 @@ ddl_type1 %type ddl_type2 ddl_type2 : COLUMN { $$ = obj_relation; } - | ddl_param_opt PARAMETER { $$ = $1; } ; -%type ddl_param_opt -ddl_param_opt - : { $$ = obj_parameter; } - | PROCEDURE { $$ = obj_procedure; } - | FUNCTION { $$ = obj_udf; } +%type ddl_type3 +ddl_type3 + : PARAMETER { $$ = obj_parameter; } + | PROCEDURE PARAMETER { $$ = obj_procedure; } + | FUNCTION PARAMETER { $$ = obj_udf; } + ; + +%type ddl_type4 +ddl_type4 + : PROCEDURE { $$ = obj_procedure; } + | EXTERNAL FUNCTION { $$ = obj_udf; } + | FUNCTION { $$ = obj_udf; } ; %type ddl_subname @@ -4784,6 +4792,18 @@ ddl_subname : '.' symbol_ddl_name { $$ = $2; } ; +%type ddl_subname_opt +ddl_subname_opt + : /* nothing */ { $$ = NULL; } + | ddl_subname + ; + +%type ddl_qualified_name +ddl_qualified_name + : symbol_ddl_name { $$ = newNode(*$1); } + | symbol_ddl_name '.' symbol_ddl_name { $$ = newNode(*$3, *$1); } + ; + %type ddl_desc ddl_desc : utf_string { $$ = $1; } diff --git a/src/isql/show.epp b/src/isql/show.epp index f62a3c3e02..6d956cf348 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -85,7 +85,7 @@ static processing_state show_all_tables(SSHORT); static void show_charsets(const SCHAR*, const SCHAR*, const bool, bool, bool, bool); static processing_state show_check(const SCHAR*); static processing_state show_collations(const SCHAR*, SSHORT sys_flag, const char* msg = 0, bool compact = false); -static void show_comment(const char* objtype, char* name1, char* name2, +static void show_comment(const char* objtype, char* packageName, char* name1, char* name2, ISC_QUAD* blobfld, const commentMode showextract, const char* banner); static processing_state show_comments(const commentMode showextract, const char* banner); static void show_db(); @@ -2668,7 +2668,7 @@ static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, co // Helper that displays in correct syntax the COMMENT ON command for each object. // It escapes identifiers with embedded double quotes and escapes the comment // itself if it contains single quotes when we are honoring script extraction. -static void show_comment(const char* objtype, char* name1, char* name2, +static void show_comment(const char* objtype, char* packageName, char* name1, char* name2, ISC_QUAD* blobfld, const commentMode showextract, const char* banner) { const bool escape_quotes = showextract == cmmExtract; @@ -2676,19 +2676,30 @@ static void show_comment(const char* objtype, char* name1, char* name2, if (escape_quotes && banner) isqlGlob.prints(banner); + if (packageName) + fb_utils::exact_name(packageName); if (name1) fb_utils::exact_name(name1); if (name2) fb_utils::exact_name(name2); + char packageNameBuffer[BUFFER_LENGTH128]; char SQL_identifier2[BUFFER_LENGTH128]; + if (escape_quotes && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION) { + if (packageName) + { + IUTILS_copy_SQL_id (packageName, packageNameBuffer, DBL_QUOTE); + packageName = packageNameBuffer; + } + if (name1) { IUTILS_copy_SQL_id (name1, SQL_identifier, DBL_QUOTE); name1 = SQL_identifier; } + if (name2) { IUTILS_copy_SQL_id (name2, SQL_identifier2, DBL_QUOTE); @@ -2698,12 +2709,21 @@ static void show_comment(const char* objtype, char* name1, char* name2, const char* quot = escape_quotes ? "'" : ""; - if (!name1) - isqlGlob.printf("COMMENT ON %-12s IS %s", objtype, quot); - else if (!name2) - isqlGlob.printf("COMMENT ON %-12s %s IS %s", objtype, name1, quot); - else - isqlGlob.printf("COMMENT ON %-12s %s.%s IS %s", objtype, name1, name2, quot); + isqlGlob.printf("COMMENT ON %-12s", objtype); + + if (packageName || name1 || name2) + isqlGlob.printf(" "); + + if (packageName) + isqlGlob.printf("%s.", packageName); + + if (name1) + isqlGlob.printf("%s", name1); + + if (name2) + isqlGlob.printf(".%s", name2); + + isqlGlob.printf(" IS %s", quot); SHOW_print_metadata_text_blob(isqlGlob.Out, blobfld, escape_quotes); isqlGlob.printf("%s%s%s", quot, isqlGlob.global_Term, NEWLINE); @@ -2740,7 +2760,7 @@ static processing_state show_comments(const commentMode showextract, const char* FOR FIRST 1 DT IN RDB$DATABASE WITH DT.RDB$DESCRIPTION NOT MISSING - show_comment("DATABASE", 0, 0, &DT.RDB$DESCRIPTION, showextract, first ? banner : 0); + show_comment("DATABASE", NULL, NULL, NULL, &DT.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR ON_ERROR @@ -2754,7 +2774,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND DM.RDB$DESCRIPTION NOT MISSING SORTED BY DM.RDB$FIELD_NAME - show_comment("DOMAIN", DM.RDB$FIELD_NAME, 0, &DM.RDB$DESCRIPTION, + show_comment("DOMAIN", NULL, DM.RDB$FIELD_NAME, NULL, &DM.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2770,7 +2790,7 @@ static processing_state show_comments(const commentMode showextract, const char* if (!RL.RDB$DESCRIPTION.NULL && !UserBlob::blobIsNull(RL.RDB$DESCRIPTION)) { - show_comment("TABLE", RL.RDB$RELATION_NAME, 0, &RL.RDB$DESCRIPTION, + show_comment("TABLE", NULL, RL.RDB$RELATION_NAME, NULL, &RL.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; } @@ -2780,7 +2800,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND RF.RDB$DESCRIPTION NOT MISSING SORTED BY RF.RDB$FIELD_POSITION - show_comment(" COLUMN", RL.RDB$RELATION_NAME, RF.RDB$FIELD_NAME, + show_comment(" COLUMN", NULL, RL.RDB$RELATION_NAME, RF.RDB$FIELD_NAME, &RF.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2802,7 +2822,7 @@ static processing_state show_comments(const commentMode showextract, const char* if (!VW.RDB$DESCRIPTION.NULL && !UserBlob::blobIsNull(VW.RDB$DESCRIPTION)) { - show_comment("VIEW", VW.RDB$RELATION_NAME, 0 , &VW.RDB$DESCRIPTION, + show_comment("VIEW", NULL, VW.RDB$RELATION_NAME, NULL, &VW.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; } @@ -2812,7 +2832,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND RF.RDB$DESCRIPTION NOT MISSING SORTED BY RF.RDB$FIELD_POSITION - show_comment(" COLUMN", VW.RDB$RELATION_NAME, RF.RDB$FIELD_NAME, + show_comment(" COLUMN", NULL, VW.RDB$RELATION_NAME, RF.RDB$FIELD_NAME, &RF.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2829,24 +2849,24 @@ static processing_state show_comments(const commentMode showextract, const char* FOR PR IN RDB$PROCEDURES WITH (PR.RDB$SYSTEM_FLAG EQ 0 OR PR.RDB$SYSTEM_FLAG MISSING) - AND PR.RDB$PACKAGE_NAME MISSING SORTED BY PR.RDB$PROCEDURE_NAME if (!PR.RDB$DESCRIPTION.NULL && !UserBlob::blobIsNull(PR.RDB$DESCRIPTION)) { - show_comment("PROCEDURE", PR.RDB$PROCEDURE_NAME, 0, &PR.RDB$DESCRIPTION, - showextract, first ? banner : 0); + show_comment("PROCEDURE", (PR.RDB$PACKAGE_NAME.NULL ? NULL : PR.RDB$PACKAGE_NAME), + PR.RDB$PROCEDURE_NAME, NULL, &PR.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; } FOR PA IN RDB$PROCEDURE_PARAMETERS WITH PA.RDB$PROCEDURE_NAME = PR.RDB$PROCEDURE_NAME - AND PA.RDB$PACKAGE_NAME MISSING + AND PA.RDB$PACKAGE_NAME EQUIV NULLIF(PR.RDB$PACKAGE_NAME, '') AND PA.RDB$DESCRIPTION NOT MISSING SORTED BY PA.RDB$PARAMETER_TYPE, PA.RDB$PARAMETER_NUMBER - show_comment(" PARAMETER", PR.RDB$PROCEDURE_NAME, PA.RDB$PARAMETER_NAME, - &PA.RDB$DESCRIPTION, showextract, first ? banner : 0); + show_comment(" PROCEDURE PARAMETER", + (PR.RDB$PACKAGE_NAME.NULL ? NULL : PR.RDB$PACKAGE_NAME), PR.RDB$PROCEDURE_NAME, + PA.RDB$PARAMETER_NAME, &PA.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR ON_ERROR @@ -2865,7 +2885,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (TR.RDB$SYSTEM_FLAG EQ 0 OR TR.RDB$SYSTEM_FLAG MISSING) SORTED BY TR.RDB$TRIGGER_NAME - show_comment("TRIGGER", TR.RDB$TRIGGER_NAME, 0, &TR.RDB$DESCRIPTION, + show_comment("TRIGGER", NULL, TR.RDB$TRIGGER_NAME, NULL, &TR.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2877,7 +2897,6 @@ static processing_state show_comments(const commentMode showextract, const char* FOR UD IN RDB$FUNCTIONS WITH UD.RDB$DESCRIPTION NOT MISSING AND (UD.RDB$SYSTEM_FLAG EQ 0 OR UD.RDB$SYSTEM_FLAG MISSING) - AND UD.RDB$PACKAGE_NAME MISSING SORTED BY UD.RDB$FUNCTION_NAME // Avoid syntax error when extracting scripts due to an historical bug in gbak. @@ -2885,9 +2904,26 @@ static processing_state show_comments(const commentMode showextract, const char* if (UserBlob::blobIsNull(UD.RDB$DESCRIPTION)) continue; - show_comment("EXTERNAL FUNCTION", UD.RDB$FUNCTION_NAME, 0, + show_comment("FUNCTION", + (UD.RDB$PACKAGE_NAME.NULL ? NULL : UD.RDB$PACKAGE_NAME), UD.RDB$FUNCTION_NAME, NULL, &UD.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; + + FOR ARG IN RDB$FUNCTION_ARGUMENTS + WITH ARG.RDB$FUNCTION_NAME = UD.RDB$FUNCTION_NAME + AND ARG.RDB$PACKAGE_NAME EQUIV NULLIF(UD.RDB$PACKAGE_NAME, '') + AND ARG.RDB$DESCRIPTION NOT MISSING + SORTED BY ARG.RDB$ARGUMENT_POSITION + + show_comment(" FUNCTION PARAMETER", + (ARG.RDB$PACKAGE_NAME.NULL ? NULL : ARG.RDB$PACKAGE_NAME), ARG.RDB$FUNCTION_NAME, + ARG.RDB$ARGUMENT_NAME, &ARG.RDB$DESCRIPTION, showextract, first ? banner : 0); + first = false; + END_FOR + ON_ERROR + ISQL_errmsg(fbStatus); + return ps_ERR; + END_ERROR END_FOR ON_ERROR ISQL_errmsg(fbStatus); @@ -2899,7 +2935,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (BF.RDB$SYSTEM_FLAG EQ 0 OR BF.RDB$SYSTEM_FLAG MISSING) SORTED BY BF.RDB$FUNCTION_NAME - show_comment("FILTER", BF.RDB$FUNCTION_NAME, 0, &BF.RDB$DESCRIPTION, + show_comment("FILTER", NULL, BF.RDB$FUNCTION_NAME, NULL, &BF.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2913,7 +2949,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (XC.RDB$SYSTEM_FLAG EQ 0 OR XC.RDB$SYSTEM_FLAG MISSING) SORTED BY XC.RDB$EXCEPTION_NAME - show_comment("EXCEPTION", XC.RDB$EXCEPTION_NAME, 0, &XC.RDB$DESCRIPTION, + show_comment("EXCEPTION", NULL, XC.RDB$EXCEPTION_NAME, NULL, &XC.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2929,7 +2965,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (GR.RDB$SYSTEM_FLAG EQ 0 OR GR.RDB$SYSTEM_FLAG MISSING) SORTED BY GR.RDB$GENERATOR_NAME - show_comment("GENERATOR", GR.RDB$GENERATOR_NAME, 0, &GR.RDB$DESCRIPTION, + show_comment("GENERATOR", NULL, GR.RDB$GENERATOR_NAME, NULL, &GR.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2944,7 +2980,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (IX.RDB$SYSTEM_FLAG EQ 0 OR IX.RDB$SYSTEM_FLAG MISSING) SORTED BY IX.RDB$INDEX_NAME - show_comment("INDEX", IX.RDB$INDEX_NAME, 0, &IX.RDB$DESCRIPTION, + show_comment("INDEX", NULL, IX.RDB$INDEX_NAME, NULL, &IX.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2960,7 +2996,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (RO.RDB$SYSTEM_FLAG EQ 0 OR RO.RDB$SYSTEM_FLAG MISSING) SORTED BY RO.RDB$ROLE_NAME - show_comment("ROLE", RO.RDB$ROLE_NAME, 0, &RO.RDB$DESCRIPTION, + show_comment("ROLE", NULL, RO.RDB$ROLE_NAME, NULL, &RO.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2977,7 +3013,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (PACK.RDB$SYSTEM_FLAG EQ 0 OR PACK.RDB$SYSTEM_FLAG MISSING) SORTED BY PACK.RDB$PACKAGE_NAME - show_comment("PACKAGE", PACK.RDB$PACKAGE_NAME, 0, &PACK.RDB$DESCRIPTION, + show_comment("PACKAGE", NULL, PACK.RDB$PACKAGE_NAME, NULL, &PACK.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -2992,7 +3028,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (CH.RDB$SYSTEM_FLAG EQ 0 OR CH.RDB$SYSTEM_FLAG MISSING) SORTED BY CH.RDB$CHARACTER_SET_NAME - show_comment("CHARACTER SET", CH.RDB$CHARACTER_SET_NAME, 0, + show_comment("CHARACTER SET", NULL, CH.RDB$CHARACTER_SET_NAME, NULL, &CH.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR @@ -3006,7 +3042,7 @@ static processing_state show_comments(const commentMode showextract, const char* AND (CL.RDB$SYSTEM_FLAG EQ 0 OR CL.RDB$SYSTEM_FLAG MISSING) SORTED BY CL.RDB$COLLATION_NAME - show_comment("COLLATION", CL.RDB$COLLATION_NAME, 0, &CL.RDB$DESCRIPTION, + show_comment("COLLATION", NULL, CL.RDB$COLLATION_NAME, NULL, &CL.RDB$DESCRIPTION, showextract, first ? banner : 0); first = false; END_FOR