From 32c3cf573bf36f576b6116983786107df5a2cb33 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Fri, 30 Jul 2021 16:35:48 -0300 Subject: [PATCH] Add SET DEBUG OPTION DSQL_KEEP_BLR and remove Statement::PREPARE_KEEP_EXEC_PATH flag. Make ISQL' SET EXEC_PATH_DISPLAY persistent between connections. --- src/common/keywords.cpp | 1 + src/dsql/DsqlCompilerScratch.h | 2 -- src/dsql/PackageNodes.epp | 2 -- src/dsql/StmtNodes.cpp | 35 +++++++++++++++++-- src/dsql/StmtNodes.h | 24 +++++++++++++ src/dsql/dsql.cpp | 19 +++++----- src/dsql/parse.y | 14 +++++++- src/include/firebird/FirebirdInterface.idl | 5 --- src/include/firebird/IdlFbInterfaces.h | 1 - src/include/gen/Firebird.pas | 1 - src/isql/isql.epp | 40 ++++++++++++++++++++-- src/jrd/Attachment.h | 23 +++++++++++++ src/jrd/jrd.cpp | 7 ++-- src/jrd/jrd_proto.h | 2 +- 14 files changed, 143 insertions(+), 33 deletions(-) diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp index 5e8c924f2a..4fab7cc0d1 100644 --- a/src/common/keywords.cpp +++ b/src/common/keywords.cpp @@ -169,6 +169,7 @@ static const TOK tokens[] = {TOK_DATEDIFF, "DATEDIFF", true}, {TOK_DAY, "DAY", false}, {TOK_DDL, "DDL", true}, + {TOK_DEBUG, "DEBUG", true}, {TOK_DEC, "DEC", false}, {TOK_DECFLOAT, "DECFLOAT", false}, {TOK_DECIMAL, "DECIMAL", false}, diff --git a/src/dsql/DsqlCompilerScratch.h b/src/dsql/DsqlCompilerScratch.h index b981658446..8ed268ed23 100644 --- a/src/dsql/DsqlCompilerScratch.h +++ b/src/dsql/DsqlCompilerScratch.h @@ -76,7 +76,6 @@ public: transaction(aTransaction), statement(aStatement), flags(0), - prepareFlags(0), nestingLevel(0), ports(p), relation(NULL), @@ -268,7 +267,6 @@ private: public: unsigned flags; // flags - unsigned prepareFlags; // prepare flags (IStatement::PREPARE*) unsigned nestingLevel; // begin...end nesting level Firebird::Array ports; // Port messages dsql_rel* relation; // relation created by this request (for DDL) diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index 14c6e19b9e..67d20b1df1 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -229,7 +229,6 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) itemScratch->clientDialect = dsqlScratch->clientDialect; itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL; - itemScratch->prepareFlags = dsqlScratch->prepareFlags; itemScratch->package = name; switch ((*items)[i].type) @@ -625,7 +624,6 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) itemScratch->clientDialect = dsqlScratch->clientDialect; itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL; - itemScratch->prepareFlags = dsqlScratch->prepareFlags; itemScratch->package = name; switch ((*arrays[i])[j].type) diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 2805270ccc..2d334d6042 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -1725,7 +1725,6 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc DsqlCompilerScratch::FLAG_FUNCTION | DsqlCompilerScratch::FLAG_SUB_ROUTINE | (dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL); - blockScratch->prepareFlags = dsqlScratch->prepareFlags; dsqlBlock = dsqlBlock->dsqlPass(blockScratch); @@ -2069,7 +2068,6 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc DsqlCompilerScratch::FLAG_PROCEDURE | DsqlCompilerScratch::FLAG_SUB_ROUTINE | (dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL); - blockScratch->prepareFlags = dsqlScratch->prepareFlags; dsqlBlock = dsqlBlock->dsqlPass(blockScratch); @@ -8587,6 +8585,39 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** /*traHan //-------------------- +SetDebugOptionNode::SetDebugOptionNode(MemoryPool& pool, MetaName* aName, ExprNode* aValue) + : SessionManagementNode(pool), + name(pool, *aName), + value(aValue) +{ +} + +void SetDebugOptionNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const +{ + SET_TDBB(tdbb); + auto& debugOptions = tdbb->getAttachment()->getDebugOptions(); + + const auto literal = nodeAs(value); + + if (!literal) + { + // This currently can happen with negative numbers. + // Since it's not relevant for DSQL_KEEP_BLR, let's throw an error. + ERR_post(Arg::Gds(isc_random) << "Invalid DEBUG option value"); + } + + const auto litDesc = &literal->litDesc; + + if (name == "DSQL_KEEP_BLR") + debugOptions.setDsqlKeepBlr(MOV_get_boolean(litDesc)); + else + ERR_post(Arg::Gds(isc_random) << "Invalid DEBUG option"); +} + + +//-------------------- + + SetDecFloatRoundNode::SetDecFloatRoundNode(MemoryPool& pool, MetaName* name) : SessionManagementNode(pool) { diff --git a/src/dsql/StmtNodes.h b/src/dsql/StmtNodes.h index 7af802d1bc..cb20d0727e 100644 --- a/src/dsql/StmtNodes.h +++ b/src/dsql/StmtNodes.h @@ -1725,6 +1725,30 @@ private: }; +class SetDebugOptionNode : public SessionManagementNode +{ +public: + SetDebugOptionNode(MemoryPool& pool, MetaName* aName, ExprNode* aValue); + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const + { + SessionManagementNode::internalPrint(printer); + + NODE_PRINT(printer, name); + NODE_PRINT(printer, value); + + return "SetDebugOptionNode"; + } + + virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const; + +private: + MetaName name; + ExprNode* value; +}; + + class SetDecFloatRoundNode : public SessionManagementNode { public: diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index b6e2fc47c4..4cf3b13059 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -82,8 +82,8 @@ using namespace Firebird; static ULONG get_request_info(thread_db*, dsql_req*, ULONG, UCHAR*); static dsql_dbb* init(Jrd::thread_db*, Jrd::Attachment*); -static dsql_req* prepareRequest(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, unsigned, bool); -static dsql_req* prepareStatement(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, unsigned, bool); +static dsql_req* prepareRequest(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, bool); +static dsql_req* prepareStatement(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, bool); static UCHAR* put_item(UCHAR, const USHORT, const UCHAR*, UCHAR*, const UCHAR* const); static void release_statement(DsqlCompiledStatement* statement); static void sql_info(thread_db*, dsql_req*, ULONG, const UCHAR*, ULONG, UCHAR*); @@ -406,7 +406,7 @@ dsql_req* DSQL_prepare(thread_db* tdbb, // Allocate a new request block and then prepare the request. request = prepareRequest(tdbb, database, transaction, length, string, dialect, - prepareFlags, isInternalRequest); + isInternalRequest); // Can not prepare a CREATE DATABASE/SCHEMA statement @@ -557,7 +557,7 @@ void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tr try { request = prepareRequest(tdbb, database, *tra_handle, length, string, dialect, - 0, isInternalRequest); + isInternalRequest); const DsqlCompiledStatement* statement = request->getStatement(); @@ -659,8 +659,7 @@ void DsqlDmlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, boo scratch->getBlrData().getCount(), scratch->getBlrData().begin(), statement->getSqlText(), scratch->getDebugData().getCount(), scratch->getDebugData().begin(), - (scratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST), - (scratch->prepareFlags & IStatement::PREPARE_KEEP_EXEC_PATH)); + (scratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST)); } catch (const Exception&) { @@ -1478,17 +1477,16 @@ static void checkD(IStatus* st) // Prepare a request for execution. Return SQL status code. // Note: caller is responsible for pool handling. static dsql_req* prepareRequest(thread_db* tdbb, dsql_dbb* database, jrd_tra* transaction, - ULONG textLength, const TEXT* text, USHORT clientDialect, unsigned prepareFlags, bool isInternalRequest) + ULONG textLength, const TEXT* text, USHORT clientDialect, bool isInternalRequest) { - return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect, - prepareFlags, isInternalRequest); + return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect, isInternalRequest); } // Prepare a statement for execution. Return SQL status code. // Note: caller is responsible for pool handling. static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra* transaction, - ULONG textLength, const TEXT* text, USHORT clientDialect, unsigned prepareFlags, bool isInternalRequest) + ULONG textLength, const TEXT* text, USHORT clientDialect, bool isInternalRequest) { Database* const dbb = tdbb->getDatabase(); @@ -1548,7 +1546,6 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra* DsqlCompilerScratch* scratch = FB_NEW_POOL(*scratchPool) DsqlCompilerScratch(*scratchPool, database, transaction, statement); - scratch->prepareFlags = prepareFlags; scratch->clientDialect = clientDialect; if (isInternalRequest) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index ecfcdadfa3..74d4e6cdcd 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -677,6 +677,10 @@ using namespace Firebird; %token CLEAR %token OLDEST +// tokens added for Firebird 4.0.1 + +%token DEBUG + // precedence declarations for expression evaluation %left OR @@ -884,7 +888,8 @@ tra_statement %type mng_statement mng_statement - : set_decfloat_round { $$ = $1; } + : set_debug_option { $$ = $1; } + | set_decfloat_round { $$ = $1; } | set_decfloat_traps { $$ = $1; } | session_statement { $$ = $1; } | set_role { $$ = $1; } @@ -5348,6 +5353,12 @@ set_role { $$ = newNode(); } ; +%type set_debug_option +set_debug_option + : SET DEBUG OPTION valid_symbol_name '=' constant + { $$ = newNode($4, $6); } + ; + %type set_decfloat_round set_decfloat_round : SET DECFLOAT ROUND valid_symbol_name @@ -9040,6 +9051,7 @@ non_reserved_word | TOTALORDER | TRAPS | ZONE + | DEBUG // added in FB 4.0.1 ; %% diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 2460607401..c1f17a346a 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -452,11 +452,6 @@ interface Statement : ReferenceCounted PREPARE_PREFETCH_METADATA | PREPARE_PREFETCH_LEGACY_PLAN | PREPARE_PREFETCH_DETAILED_PLAN | PREPARE_PREFETCH_AFFECTED_RECORDS; - // Keep the execution path information to be retrieved with getInfo and isc_info_sql_exec_path_* - // Warning: this feature is very tied to engine internals and its usage is discouraged if you do - // not understand very well how these internals are subject to change between versions. - const uint PREPARE_KEEP_EXEC_PATH = 0x80; - // Statement flags. const uint FLAG_HAS_CURSOR = 0x01; const uint FLAG_REPEAT_EXECUTE = 0x02; diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index 00888c95a3..37de20117f 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -1718,7 +1718,6 @@ namespace Firebird static const unsigned PREPARE_PREFETCH_FLAGS = 0x40; static const unsigned PREPARE_PREFETCH_METADATA = IStatement::PREPARE_PREFETCH_TYPE | IStatement::PREPARE_PREFETCH_FLAGS | IStatement::PREPARE_PREFETCH_INPUT_PARAMETERS | IStatement::PREPARE_PREFETCH_OUTPUT_PARAMETERS; static const unsigned PREPARE_PREFETCH_ALL = IStatement::PREPARE_PREFETCH_METADATA | IStatement::PREPARE_PREFETCH_LEGACY_PLAN | IStatement::PREPARE_PREFETCH_DETAILED_PLAN | IStatement::PREPARE_PREFETCH_AFFECTED_RECORDS; - static const unsigned PREPARE_KEEP_EXEC_PATH = 0x80; static const unsigned FLAG_HAS_CURSOR = 0x1; static const unsigned FLAG_REPEAT_EXECUTE = 0x2; static const unsigned CURSOR_TYPE_SCROLLABLE = 0x1; diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 3b3dd35b64..8e684c3388 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -1457,7 +1457,6 @@ type const PREPARE_PREFETCH_FLAGS = Cardinal($40); const PREPARE_PREFETCH_METADATA = Cardinal(IStatement.PREPARE_PREFETCH_TYPE or IStatement.PREPARE_PREFETCH_FLAGS or IStatement.PREPARE_PREFETCH_INPUT_PARAMETERS or IStatement.PREPARE_PREFETCH_OUTPUT_PARAMETERS); const PREPARE_PREFETCH_ALL = Cardinal(IStatement.PREPARE_PREFETCH_METADATA or IStatement.PREPARE_PREFETCH_LEGACY_PLAN or IStatement.PREPARE_PREFETCH_DETAILED_PLAN or IStatement.PREPARE_PREFETCH_AFFECTED_RECORDS); - const PREPARE_KEEP_EXEC_PATH = Cardinal($80); const FLAG_HAS_CURSOR = Cardinal($1); const FLAG_REPEAT_EXECUTE = Cardinal($2); const CURSOR_TYPE_SCROLLABLE = Cardinal($1); diff --git a/src/isql/isql.epp b/src/isql/isql.epp index f601a08255..34296a1fb8 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -368,6 +368,7 @@ static processing_state drop_db(); static processing_state edit(const TEXT* const*); static processing_state end_trans(); static processing_state escape(const TEXT*); +static processing_state execSetDebugCommand(); static processing_state frontend(const TEXT*); static processing_state frontend_set(const char* cmd, const char* const* parms, const char* const* lparms, char* const bad_dialect_buf, bool& bad_dialect); @@ -4790,6 +4791,27 @@ static processing_state escape(const TEXT* cmd) } +static processing_state execSetDebugCommand() +{ + if (!DB) + return SKIP; + + const char* stmt = setValues.ExecPathDisplay[0] ? + "set debug option dsql_keep_blr = true" : + "set debug option dsql_keep_blr = false"; + + DB->execute(fbStatus, nullptr, 0, stmt, isqlGlob.SQL_dialect, nullptr, nullptr, nullptr, nullptr); + + if (setValues.ExecPathDisplay[0] && (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)) + { + STDERROUT("SET EXEC_PATH_DISPLAY is not supported in this connection."); + return FAIL; + } + + return SKIP; +} + + static processing_state frontend(const TEXT* statement) { /************************************** @@ -5357,7 +5379,10 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, case SetOptions::exec_path_display: ret = SKIP; - if (strcmp(parms[2], "OFF") == 0) + + if (!*parms[2]) + ret = ps_ERR; + else if (strcmp(parms[2], "OFF") == 0) setValues.ExecPathDisplay[0] = 0; else { @@ -5396,6 +5421,10 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, ret = ps_ERR; } } + + if (ret != ps_ERR) + ret = execSetDebugCommand(); + break; case SetOptions::sql: @@ -6100,6 +6129,9 @@ void ISQL_get_version(bool call_by_create_db) isqlGlob.db_SQL_dialect = global_dialect_spoken; else isqlGlob.db_SQL_dialect = SQL_DIALECT_V5; + + if (setValues.ExecPathDisplay[0]) + execSetDebugCommand(); } @@ -6761,6 +6793,9 @@ static processing_state newdb(TEXT* dbname, } } + if (setValues.ExecPathDisplay[0]) + execSetDebugCommand(); + global_Stmt = NULL; return SKIP; @@ -8852,8 +8887,7 @@ static processing_state process_statement(const TEXT* str2) } global_Stmt = DB->prepare(fbStatus, prepare_trans, 0, str2, isqlGlob.SQL_dialect, - Firebird::IStatement::PREPARE_PREFETCH_METADATA | - (setValues.ExecPathDisplay[0] ? Firebird::IStatement::PREPARE_KEEP_EXEC_PATH : 0)); + Firebird::IStatement::PREPARE_PREFETCH_METADATA); if (failed()) { if (isqlGlob.SQL_dialect == SQL_DIALECT_V6_TRANSITION && Input_file) diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index f56da7ff14..0c085c2288 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -401,6 +401,23 @@ public: USHORT originalTimeZone = Firebird::TimeZoneUtil::GMT_ZONE; }; + class DebugOptions + { + public: + bool getDsqlKeepBlr() const + { + return dsqlKeepBlr; + } + + void setDsqlKeepBlr(bool value) + { + dsqlKeepBlr = value; + } + + private: + bool dsqlKeepBlr = false; + }; + public: static Attachment* create(Database* dbb, JProvider* provider); static void destroy(Attachment* const attachment); @@ -656,6 +673,11 @@ public: return att_initial_options.getBindings(); } + DebugOptions& getDebugOptions() + { + return att_debug_options; + } + void checkReplSetLock(thread_db* tdbb); void invalidateReplSet(thread_db* tdbb, bool broadcast); @@ -677,6 +699,7 @@ private: Firebird::Array att_batches; InitialOptions att_initial_options; // Initial session options + DebugOptions att_debug_options; Lock* att_repl_lock; // Replication set lock JProvider* att_provider; // Provider which created this attachment diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index b896059c90..38fd0d5dc9 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -2646,7 +2646,7 @@ JRequest* JAttachment::compileRequest(CheckStatusWrapper* user_status, try { jrd_req* request = NULL; - JRD_compile(tdbb, getHandle(), &request, blr_length, blr, RefStrPtr(), 0, NULL, false, false); + JRD_compile(tdbb, getHandle(), &request, blr_length, blr, RefStrPtr(), 0, NULL, false); stmt = request->getStatement(); trace.finish(request, ITracePlugin::RESULT_SUCCESS); @@ -9189,8 +9189,7 @@ void JRD_compile(thread_db* tdbb, RefStrPtr ref_str, ULONG dbginfo_length, const UCHAR* dbginfo, - bool isInternalRequest, - bool preserveBlrData) + bool isInternalRequest) { /************************************** * @@ -9216,7 +9215,7 @@ void JRD_compile(thread_db* tdbb, fb_assert(statement->blr.isEmpty()); - if (preserveBlrData) + if (attachment->getDebugOptions().getDsqlKeepBlr()) statement->blr.insert(0, blr, blr_length); *req_handle = request; diff --git a/src/jrd/jrd_proto.h b/src/jrd/jrd_proto.h index cc859b4fbc..b1569e0fba 100644 --- a/src/jrd/jrd_proto.h +++ b/src/jrd/jrd_proto.h @@ -73,7 +73,7 @@ void JRD_start_transaction(Jrd::thread_db* tdbb, Jrd::jrd_tra** transaction, void JRD_unwind_request(Jrd::thread_db* tdbb, Jrd::jrd_req* request); void JRD_compile(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, Jrd::jrd_req** req_handle, ULONG blr_length, const UCHAR* blr, Firebird::RefStrPtr, - ULONG dbginfo_length, const UCHAR* dbginfo, bool isInternalRequest, bool preserveBlrData); + ULONG dbginfo_length, const UCHAR* dbginfo, bool isInternalRequest); bool JRD_verify_database_access(const Firebird::PathName&); void JRD_shutdown_attachment(Jrd::Attachment* attachment); void JRD_shutdown_attachments(Jrd::Database* dbb);