diff --git a/doc/README.isql_enhancements.txt b/doc/README.isql_enhancements.txt index cdff772a86..43398b85af 100644 --- a/doc/README.isql_enhancements.txt +++ b/doc/README.isql_enhancements.txt @@ -163,13 +163,13 @@ Isql enhancements in Firebird v3. Author: Vladyslav Khorsun -When set to ON, isql keeps text of following successful SET TRANSACTION statement and -new DML transactions is started using the same SQL text (instead of defaul CONCURRENCY +When set to ON, isql keeps text of following successful SET TRANSACTION statement and +new DML transactions is started using the same SQL text (instead of defaul CONCURRENCY WAIT mode). When set to OFF, isql start new DML transaction as usual. Name KEEP_TRAN_PARAMS could be cut down to the KEEP_TRAN. -In Firebird 3 KEEP_TRAN_PARAMS value is OFF by default, preserving backward compatibility +In Firebird 3 KEEP_TRAN_PARAMS value is OFF by default, preserving backward compatibility with old behaviour. In Firebird 4 KEEP_TRAN_PARAMS is ON by default to make isql behaviour more logical. @@ -191,7 +191,7 @@ SET TRANSACTION SQL>commit; --- start new transaction, check KEEP_TRAN value and actual transaction's +-- start new transaction, check KEEP_TRAN value and actual transaction's -- parameters SQL>SET TRANSACTION READ COMMITTED WAIT; SQL>SET; @@ -237,4 +237,17 @@ SNAPSHOT SQL> SET; ... Keep transaction params: OFF -SQL> +SQL> + + + +Isql enhancements in Firebird v5. +--------------------------------- + +10) SET EXEC_PATH_DISPLAY BLR/OFF + +Retrieves the execution path of a DML statement formatted as BLR text. + +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. diff --git a/src/dsql/DsqlCompilerScratch.h b/src/dsql/DsqlCompilerScratch.h index 8ed268ed23..b981658446 100644 --- a/src/dsql/DsqlCompilerScratch.h +++ b/src/dsql/DsqlCompilerScratch.h @@ -76,6 +76,7 @@ public: transaction(aTransaction), statement(aStatement), flags(0), + prepareFlags(0), nestingLevel(0), ports(p), relation(NULL), @@ -267,6 +268,7 @@ 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 67d20b1df1..14c6e19b9e 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -229,6 +229,7 @@ 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) @@ -624,6 +625,7 @@ 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 01975eb077..2805270ccc 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -1725,6 +1725,7 @@ 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); @@ -2064,8 +2065,11 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc blockScratch = FB_NEW_POOL(pool) DsqlCompilerScratch(pool, dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement, dsqlScratch); blockScratch->clientDialect = dsqlScratch->clientDialect; - blockScratch->flags |= DsqlCompilerScratch::FLAG_PROCEDURE | DsqlCompilerScratch::FLAG_SUB_ROUTINE; - blockScratch->flags |= dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL; + blockScratch->flags |= + DsqlCompilerScratch::FLAG_PROCEDURE | + DsqlCompilerScratch::FLAG_SUB_ROUTINE | + (dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL); + blockScratch->prepareFlags = dsqlScratch->prepareFlags; dsqlBlock = dsqlBlock->dsqlPass(blockScratch); diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index 5cf343d4c7..e2c65e280a 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, bool); -static dsql_req* prepareStatement(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, bool); +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 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*); @@ -288,7 +288,7 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer) UCHAR* dsqlMsgBuffer = req_msg_buffers[message->msg_buffer_number]; if (!firstRowFetched && needRestarts()) { - // Note: tra_handle can't be changed by executeReceiveWithRestarts below + // Note: tra_handle can't be changed by executeReceiveWithRestarts below // and outMetadata and outMsg in not used there, so passing NULL's is safe. jrd_tra* tra = req_transaction; @@ -392,7 +392,7 @@ void DSQL_free_statement(thread_db* tdbb, dsql_req* request, USHORT option) **/ dsql_req* DSQL_prepare(thread_db* tdbb, Attachment* attachment, jrd_tra* transaction, - ULONG length, const TEXT* string, USHORT dialect, + ULONG length, const TEXT* string, USHORT dialect, unsigned prepareFlags, Array* items, Array* buffer, bool isInternalRequest) { @@ -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, - isInternalRequest); + prepareFlags, 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, - isInternalRequest); + 0, isInternalRequest); const DsqlCompiledStatement* statement = request->getStatement(); @@ -659,7 +659,8 @@ 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->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST), + (scratch->prepareFlags & IStatement::PREPARE_KEEP_EXEC_PATH)); } catch (const Exception&) { @@ -940,7 +941,7 @@ void DsqlDmlRequest::executeReceiveWithRestarts(thread_db* tdbb, jrd_tra** traHa "\tQuery:\n%s\n", numTries, req_request->getStatement()->sqlText->c_str() ); } - // When restart we must execute query + // When restart we must execute query exec = true; } } @@ -1477,17 +1478,17 @@ 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, bool isInternalRequest) + ULONG textLength, const TEXT* text, USHORT clientDialect, unsigned prepareFlags, bool isInternalRequest) { return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect, - isInternalRequest); + prepareFlags, 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, bool isInternalRequest) + ULONG textLength, const TEXT* text, USHORT clientDialect, unsigned prepareFlags, bool isInternalRequest) { Database* const dbb = tdbb->getDatabase(); @@ -1547,6 +1548,7 @@ 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) @@ -2223,6 +2225,59 @@ static void sql_info(thread_db* tdbb, } break; + case isc_info_sql_exec_path_blr_bytes: + case isc_info_sql_exec_path_blr_text: + { + HalfStaticArray path; + + if (request->req_request && request->req_request->getStatement()) + { + const auto& blr = request->req_request->getStatement()->blr; + + if (blr.hasData()) + { + if (item == isc_info_sql_exec_path_blr_bytes) + path.push(blr.begin(), blr.getCount()); + else if (item == isc_info_sql_exec_path_blr_text) + { + fb_print_blr(blr.begin(), (ULONG) blr.getCount(), + [](void* arg, SSHORT offset, const char* line) + { + auto& localPath = *static_cast(arg); + auto lineLen = strlen(line); + char offsetStr[10]; + auto offsetLen = sprintf(offsetStr, "%5d", (int) offset); + + localPath.push(reinterpret_cast(offsetStr), offsetLen); + localPath.push(' '); + localPath.push(reinterpret_cast(line), lineLen); + localPath.push('\n'); + }, + &path, 0); + } + } + } + + if (path.hasData()) + { + // 1-byte item + 2-byte length + isc_info_end/isc_info_truncated == 4 + const ULONG bufferLength = end_info - info - 4; + const ULONG maxLength = MIN(bufferLength, MAX_USHORT); + + if (path.getCount() > maxLength) + { + *info = isc_info_truncated; + info = NULL; + } + else + info = put_item(item, path.getCount(), path.begin(), info, end_info); + } + + if (!info) + return; + } + break; + case isc_info_sql_num_variables: case isc_info_sql_describe_vars: if (messageFound) diff --git a/src/dsql/dsql_proto.h b/src/dsql/dsql_proto.h index a1e40edd96..dfd44e6d4d 100644 --- a/src/dsql/dsql_proto.h +++ b/src/dsql/dsql_proto.h @@ -44,7 +44,7 @@ Jrd::DsqlCursor* DSQL_open(Jrd::thread_db*, Jrd::jrd_tra**, Jrd::dsql_req*, Firebird::IMessageMetadata*, const UCHAR*, Firebird::IMessageMetadata*, ULONG); Jrd::dsql_req* DSQL_prepare(Jrd::thread_db*, Jrd::Attachment*, Jrd::jrd_tra*, ULONG, const TEXT*, - USHORT, Firebird::Array*, Firebird::Array*, bool); + USHORT, unsigned, Firebird::Array*, Firebird::Array*, bool); void DSQL_sql_info(Jrd::thread_db*, Jrd::dsql_req*, ULONG, const UCHAR*, ULONG, UCHAR*); diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index c1f17a346a..2460607401 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -452,6 +452,11 @@ 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 37de20117f..00888c95a3 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -1718,6 +1718,7 @@ 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/firebird/impl/inf_pub.h b/src/include/firebird/impl/inf_pub.h index a4c7f1ec04..ca4240fb65 100644 --- a/src/include/firebird/impl/inf_pub.h +++ b/src/include/firebird/impl/inf_pub.h @@ -478,6 +478,8 @@ enum info_db_provider #define isc_info_sql_stmt_timeout_user 28 #define isc_info_sql_stmt_timeout_run 29 #define isc_info_sql_stmt_blob_align 30 +#define isc_info_sql_exec_path_blr_bytes 31 +#define isc_info_sql_exec_path_blr_text 32 /*********************************/ /* SQL information return values */ diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 8e684c3388..3b3dd35b64 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -1457,6 +1457,7 @@ 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 99931dc978..7b8ed60c6c 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -400,6 +400,7 @@ static processing_state print_performance(const SINT64* perf_before); static void print_message(Firebird::IMessageMetadata* msg, const char* dir); static void process_header(Firebird::IMessageMetadata*, const unsigned pad[], TEXT header[], TEXT header2[]); static void process_plan(); +static void process_exec_path(); static SINT64 process_record_count(const unsigned statement_type); static unsigned process_message_display(Firebird::IMessageMetadata* msg, unsigned pad[]); static processing_state process_statement(const TEXT*); @@ -457,6 +458,7 @@ public: Echo = false; Time_display = false; Sqlda_display = false; + ExecPathDisplay[0] = 0; Stats = false; Autocommit = true; // Commit ddl Warnings = true; // Print warnings @@ -480,6 +482,7 @@ public: bool Echo; bool Time_display; bool Sqlda_display; + UCHAR ExecPathDisplay[10]; bool Stats; bool Autocommit; // Commit ddl bool Warnings; // Print warnings @@ -5172,9 +5175,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, { stat, count, list, plan, planonly, explain, blobdisplay, echo, autoddl, width, transaction, terminator, names, time, -//#ifdef DEV_BUILD sqlda_display, -//#endif + exec_path_display, sql, warning, sqlCont, heading, bail, bulk_insert, maxrows, stmtTimeout, keepTranParams, @@ -5201,9 +5203,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, {SetOptions::terminator, "TERMINATOR", 4}, {SetOptions::names, "NAMES", 0}, {SetOptions::time, "TIME", 0}, -//#ifdef DEV_BUILD {SetOptions::sqlda_display, "SQLDA_DISPLAY", 0}, -//#endif + {SetOptions::exec_path_display, "EXEC_PATH_DISPLAY", 0}, {SetOptions::sql, "SQL", 0}, {SetOptions::warning, "WARNINGS", 7}, {SetOptions::warning, "WNG", 0}, @@ -5347,11 +5348,52 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, ret = do_set_command(parms[2], &setValues.Time_display); break; -//#ifdef DEV_BUILD case SetOptions::sqlda_display: ret = do_set_command(parms[2], &setValues.Sqlda_display); break; -//#endif // DEV_BUILD + + case SetOptions::exec_path_display: + ret = SKIP; + if (strcmp(parms[2], "OFF") == 0) + setValues.ExecPathDisplay[0] = 0; + else + { + Firebird::Array execPath; + + for (int parNum = 2; parNum < MAX_TERMS - 1 && *parms[parNum]; ++parNum) + { + const char* param = parms[parNum]; + UCHAR code; + + if (strcmp(param, "BLR") == 0) + code = isc_info_sql_exec_path_blr_text; + else + { + ret = ps_ERR; + break; + } + + if (execPath.exist(code)) + { + ret = ps_ERR; + break; + } + + execPath.push(code); + } + + if (ret != ps_ERR) + { + if (execPath.getCount() < sizeof(setValues.ExecPathDisplay)) + { + memcpy(setValues.ExecPathDisplay, execPath.begin(), execPath.getCount()); + setValues.ExecPathDisplay[execPath.getCount()] = 0; + } + else + ret = ps_ERR; + } + } + break; case SetOptions::sql: if (!strcmp(parms[2], "DIALECT")) @@ -8366,6 +8408,58 @@ static void process_plan() } +static void process_exec_path() +{ + if (!global_Stmt) + return; + + Firebird::Array pathBuffer; + pathBuffer.getBuffer(MAX_USHORT, false); + + for (const UCHAR* code = setValues.ExecPathDisplay; *code; ++code) + { + global_Stmt->getInfo(fbStatus, 1, code, pathBuffer.getCount(), pathBuffer.begin()); + + if (ISQL_errmsg(fbStatus)) + return; + + Firebird::string pathString; + + for (const UCHAR* ptr = pathBuffer.begin(); ptr < pathBuffer.end();) + { + const UCHAR tag = *ptr++; + + if (tag == *code) + { + const USHORT len = (USHORT) gds__vax_integer(ptr, sizeof(USHORT)); + ptr += sizeof(USHORT); + pathString.assign((const char*) ptr, len); + ptr += len; + } + else if (tag == isc_info_end) + break; + else if (tag == isc_info_truncated) + { + pathString = "* error: overflow *\n"; + break; + } + else + pathString = "* unknown error *\n"; + } + + if (pathString.hasData()) + { + IUTILS_printf2(Diag, "%sExecution path (%s):%s%s%s", NEWLINE, + (*code == isc_info_sql_exec_path_blr_text ? "BLR" : + "* unknown *" + ), + NEWLINE, NEWLINE, + pathString.c_str()); + } + } +} + + // *************************************** // p r o c e s s _ r e c o r d _ c o u n t // *************************************** @@ -8664,7 +8758,8 @@ 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); + Firebird::IStatement::PREPARE_PREFETCH_METADATA | + (setValues.ExecPathDisplay[0] ? Firebird::IStatement::PREPARE_KEEP_EXEC_PATH : 0)); if (failed()) { if (isqlGlob.SQL_dialect == SQL_DIALECT_V6_TRANSITION && Input_file) @@ -8738,7 +8833,6 @@ static processing_state process_statement(const TEXT* str2) } } - const bool is_selectable = statement_type == isc_info_sql_stmt_select || statement_type == isc_info_sql_stmt_select_for_upd || @@ -8757,6 +8851,9 @@ static processing_state process_statement(const TEXT* str2) } } + if (setValues.ExecPathDisplay[0]) + process_exec_path(); + // If the statement isn't a select, execute it and be done if (!is_selectable && !setValues.Planonly) diff --git a/src/jrd/PreparedStatement.cpp b/src/jrd/PreparedStatement.cpp index 3468ea300d..e58a309d3d 100644 --- a/src/jrd/PreparedStatement.cpp +++ b/src/jrd/PreparedStatement.cpp @@ -322,7 +322,7 @@ void PreparedStatement::init(thread_db* tdbb, Attachment* attachment, jrd_tra* t const int dialect = isInternalRequest || (dbb.dbb_flags & DBB_DB_SQL_dialect_3) ? SQL_DIALECT_V6 : SQL_DIALECT_V5; - request = DSQL_prepare(tdbb, attachment, transaction, text.length(), text.c_str(), dialect, + request = DSQL_prepare(tdbb, attachment, transaction, text.length(), text.c_str(), dialect, 0, NULL, NULL, isInternalRequest); const DsqlCompiledStatement* statement = request->getStatement(); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 4ce22161f0..b896059c90 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); + JRD_compile(tdbb, getHandle(), &request, blr_length, blr, RefStrPtr(), 0, NULL, false, false); stmt = request->getStatement(); trace.finish(request, ITracePlugin::RESULT_SUCCESS); @@ -5444,7 +5444,7 @@ JStatement* JAttachment::prepare(CheckStatusWrapper* user_status, ITransaction* // observation for now. StatementMetadata::buildInfoItems(items, flags); - statement = DSQL_prepare(tdbb, getHandle(), tra, stmtLength, sqlStmt, dialect, + statement = DSQL_prepare(tdbb, getHandle(), tra, stmtLength, sqlStmt, dialect, flags, &items, &buffer, false); rc = FB_NEW JStatement(statement, getStable(), buffer); rc->addRef(); @@ -9189,7 +9189,8 @@ void JRD_compile(thread_db* tdbb, RefStrPtr ref_str, ULONG dbginfo_length, const UCHAR* dbginfo, - bool isInternalRequest) + bool isInternalRequest, + bool preserveBlrData) { /************************************** * @@ -9210,20 +9211,14 @@ void JRD_compile(thread_db* tdbb, JrdStatement* statement = request->getStatement(); - if (!ref_str) - { - fb_assert(statement->blr.isEmpty()); - - // hvlad: if\when we implement request's cache in the future and - // CMP_compile2 will return us previously compiled request with - // non-empty req_blr, then we must replace assertion by the line below - // if (!statement->req_blr.isEmpty()) - - statement->blr.insert(0, blr, blr_length); - } - else + if (ref_str) statement->sqlText = ref_str; + fb_assert(statement->blr.isEmpty()); + + if (preserveBlrData) + 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 b1569e0fba..cc859b4fbc 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); + ULONG dbginfo_length, const UCHAR* dbginfo, bool isInternalRequest, bool preserveBlrData); bool JRD_verify_database_access(const Firebird::PathName&); void JRD_shutdown_attachment(Jrd::Attachment* attachment); void JRD_shutdown_attachments(Jrd::Database* dbb);