mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 22:43:03 +01:00
Feature #6910 - Add way to retrieve statement BLR with Statement::getInfo and ISQL's SET EXEC_PATH_DISPLAY BLR.
This commit is contained in:
parent
63b87dcde7
commit
c93e8489fb
@ -238,3 +238,16 @@ SQL> SET;
|
|||||||
...
|
...
|
||||||
Keep transaction params: OFF
|
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.
|
||||||
|
@ -76,6 +76,7 @@ public:
|
|||||||
transaction(aTransaction),
|
transaction(aTransaction),
|
||||||
statement(aStatement),
|
statement(aStatement),
|
||||||
flags(0),
|
flags(0),
|
||||||
|
prepareFlags(0),
|
||||||
nestingLevel(0),
|
nestingLevel(0),
|
||||||
ports(p),
|
ports(p),
|
||||||
relation(NULL),
|
relation(NULL),
|
||||||
@ -267,6 +268,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned flags; // flags
|
unsigned flags; // flags
|
||||||
|
unsigned prepareFlags; // prepare flags (IStatement::PREPARE*)
|
||||||
unsigned nestingLevel; // begin...end nesting level
|
unsigned nestingLevel; // begin...end nesting level
|
||||||
Firebird::Array<dsql_msg*> ports; // Port messages
|
Firebird::Array<dsql_msg*> ports; // Port messages
|
||||||
dsql_rel* relation; // relation created by this request (for DDL)
|
dsql_rel* relation; // relation created by this request (for DDL)
|
||||||
|
@ -229,6 +229,7 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
itemScratch->clientDialect = dsqlScratch->clientDialect;
|
itemScratch->clientDialect = dsqlScratch->clientDialect;
|
||||||
itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL;
|
itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL;
|
||||||
|
itemScratch->prepareFlags = dsqlScratch->prepareFlags;
|
||||||
itemScratch->package = name;
|
itemScratch->package = name;
|
||||||
|
|
||||||
switch ((*items)[i].type)
|
switch ((*items)[i].type)
|
||||||
@ -624,6 +625,7 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
itemScratch->clientDialect = dsqlScratch->clientDialect;
|
itemScratch->clientDialect = dsqlScratch->clientDialect;
|
||||||
itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL;
|
itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL;
|
||||||
|
itemScratch->prepareFlags = dsqlScratch->prepareFlags;
|
||||||
itemScratch->package = name;
|
itemScratch->package = name;
|
||||||
|
|
||||||
switch ((*arrays[i])[j].type)
|
switch ((*arrays[i])[j].type)
|
||||||
|
@ -1725,6 +1725,7 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
|
|||||||
DsqlCompilerScratch::FLAG_FUNCTION |
|
DsqlCompilerScratch::FLAG_FUNCTION |
|
||||||
DsqlCompilerScratch::FLAG_SUB_ROUTINE |
|
DsqlCompilerScratch::FLAG_SUB_ROUTINE |
|
||||||
(dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL);
|
(dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL);
|
||||||
|
blockScratch->prepareFlags = dsqlScratch->prepareFlags;
|
||||||
|
|
||||||
dsqlBlock = dsqlBlock->dsqlPass(blockScratch);
|
dsqlBlock = dsqlBlock->dsqlPass(blockScratch);
|
||||||
|
|
||||||
@ -2064,8 +2065,11 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
|
|||||||
blockScratch = FB_NEW_POOL(pool) DsqlCompilerScratch(pool,
|
blockScratch = FB_NEW_POOL(pool) DsqlCompilerScratch(pool,
|
||||||
dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement, dsqlScratch);
|
dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement, dsqlScratch);
|
||||||
blockScratch->clientDialect = dsqlScratch->clientDialect;
|
blockScratch->clientDialect = dsqlScratch->clientDialect;
|
||||||
blockScratch->flags |= DsqlCompilerScratch::FLAG_PROCEDURE | DsqlCompilerScratch::FLAG_SUB_ROUTINE;
|
blockScratch->flags |=
|
||||||
blockScratch->flags |= dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL;
|
DsqlCompilerScratch::FLAG_PROCEDURE |
|
||||||
|
DsqlCompilerScratch::FLAG_SUB_ROUTINE |
|
||||||
|
(dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL);
|
||||||
|
blockScratch->prepareFlags = dsqlScratch->prepareFlags;
|
||||||
|
|
||||||
dsqlBlock = dsqlBlock->dsqlPass(blockScratch);
|
dsqlBlock = dsqlBlock->dsqlPass(blockScratch);
|
||||||
|
|
||||||
|
@ -82,8 +82,8 @@ using namespace Firebird;
|
|||||||
|
|
||||||
static ULONG get_request_info(thread_db*, dsql_req*, ULONG, UCHAR*);
|
static ULONG get_request_info(thread_db*, dsql_req*, ULONG, UCHAR*);
|
||||||
static dsql_dbb* init(Jrd::thread_db*, Jrd::Attachment*);
|
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* 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, 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 UCHAR* put_item(UCHAR, const USHORT, const UCHAR*, UCHAR*, const UCHAR* const);
|
||||||
static void release_statement(DsqlCompiledStatement* statement);
|
static void release_statement(DsqlCompiledStatement* statement);
|
||||||
static void sql_info(thread_db*, dsql_req*, ULONG, const UCHAR*, ULONG, UCHAR*);
|
static void sql_info(thread_db*, dsql_req*, ULONG, const UCHAR*, ULONG, UCHAR*);
|
||||||
@ -392,7 +392,7 @@ void DSQL_free_statement(thread_db* tdbb, dsql_req* request, USHORT option)
|
|||||||
**/
|
**/
|
||||||
dsql_req* DSQL_prepare(thread_db* tdbb,
|
dsql_req* DSQL_prepare(thread_db* tdbb,
|
||||||
Attachment* attachment, jrd_tra* transaction,
|
Attachment* attachment, jrd_tra* transaction,
|
||||||
ULONG length, const TEXT* string, USHORT dialect,
|
ULONG length, const TEXT* string, USHORT dialect, unsigned prepareFlags,
|
||||||
Array<UCHAR>* items, Array<UCHAR>* buffer,
|
Array<UCHAR>* items, Array<UCHAR>* buffer,
|
||||||
bool isInternalRequest)
|
bool isInternalRequest)
|
||||||
{
|
{
|
||||||
@ -406,7 +406,7 @@ dsql_req* DSQL_prepare(thread_db* tdbb,
|
|||||||
// Allocate a new request block and then prepare the request.
|
// Allocate a new request block and then prepare the request.
|
||||||
|
|
||||||
request = prepareRequest(tdbb, database, transaction, length, string, dialect,
|
request = prepareRequest(tdbb, database, transaction, length, string, dialect,
|
||||||
isInternalRequest);
|
prepareFlags, isInternalRequest);
|
||||||
|
|
||||||
// Can not prepare a CREATE DATABASE/SCHEMA statement
|
// 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
|
try
|
||||||
{
|
{
|
||||||
request = prepareRequest(tdbb, database, *tra_handle, length, string, dialect,
|
request = prepareRequest(tdbb, database, *tra_handle, length, string, dialect,
|
||||||
isInternalRequest);
|
0, isInternalRequest);
|
||||||
|
|
||||||
const DsqlCompiledStatement* statement = request->getStatement();
|
const DsqlCompiledStatement* statement = request->getStatement();
|
||||||
|
|
||||||
@ -659,7 +659,8 @@ void DsqlDmlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, boo
|
|||||||
scratch->getBlrData().getCount(), scratch->getBlrData().begin(),
|
scratch->getBlrData().getCount(), scratch->getBlrData().begin(),
|
||||||
statement->getSqlText(),
|
statement->getSqlText(),
|
||||||
scratch->getDebugData().getCount(), scratch->getDebugData().begin(),
|
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&)
|
catch (const Exception&)
|
||||||
{
|
{
|
||||||
@ -1477,17 +1478,17 @@ static void checkD(IStatus* st)
|
|||||||
// Prepare a request for execution. Return SQL status code.
|
// Prepare a request for execution. Return SQL status code.
|
||||||
// Note: caller is responsible for pool handling.
|
// Note: caller is responsible for pool handling.
|
||||||
static dsql_req* prepareRequest(thread_db* tdbb, dsql_dbb* database, jrd_tra* transaction,
|
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,
|
return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect,
|
||||||
isInternalRequest);
|
prepareFlags, isInternalRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Prepare a statement for execution. Return SQL status code.
|
// Prepare a statement for execution. Return SQL status code.
|
||||||
// Note: caller is responsible for pool handling.
|
// Note: caller is responsible for pool handling.
|
||||||
static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra* transaction,
|
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();
|
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,
|
DsqlCompilerScratch* scratch = FB_NEW_POOL(*scratchPool) DsqlCompilerScratch(*scratchPool, database,
|
||||||
transaction, statement);
|
transaction, statement);
|
||||||
|
scratch->prepareFlags = prepareFlags;
|
||||||
scratch->clientDialect = clientDialect;
|
scratch->clientDialect = clientDialect;
|
||||||
|
|
||||||
if (isInternalRequest)
|
if (isInternalRequest)
|
||||||
@ -2223,6 +2225,59 @@ static void sql_info(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isc_info_sql_exec_path_blr_bytes:
|
||||||
|
case isc_info_sql_exec_path_blr_text:
|
||||||
|
{
|
||||||
|
HalfStaticArray<UCHAR, 128> 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<decltype(path)*>(arg);
|
||||||
|
auto lineLen = strlen(line);
|
||||||
|
char offsetStr[10];
|
||||||
|
auto offsetLen = sprintf(offsetStr, "%5d", (int) offset);
|
||||||
|
|
||||||
|
localPath.push(reinterpret_cast<const UCHAR*>(offsetStr), offsetLen);
|
||||||
|
localPath.push(' ');
|
||||||
|
localPath.push(reinterpret_cast<const UCHAR*>(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_num_variables:
|
||||||
case isc_info_sql_describe_vars:
|
case isc_info_sql_describe_vars:
|
||||||
if (messageFound)
|
if (messageFound)
|
||||||
|
@ -44,7 +44,7 @@ Jrd::DsqlCursor* DSQL_open(Jrd::thread_db*, Jrd::jrd_tra**, Jrd::dsql_req*,
|
|||||||
Firebird::IMessageMetadata*, const UCHAR*,
|
Firebird::IMessageMetadata*, const UCHAR*,
|
||||||
Firebird::IMessageMetadata*, ULONG);
|
Firebird::IMessageMetadata*, ULONG);
|
||||||
Jrd::dsql_req* DSQL_prepare(Jrd::thread_db*, Jrd::Attachment*, Jrd::jrd_tra*, ULONG, const TEXT*,
|
Jrd::dsql_req* DSQL_prepare(Jrd::thread_db*, Jrd::Attachment*, Jrd::jrd_tra*, ULONG, const TEXT*,
|
||||||
USHORT, Firebird::Array<UCHAR>*, Firebird::Array<UCHAR>*, bool);
|
USHORT, unsigned, Firebird::Array<UCHAR>*, Firebird::Array<UCHAR>*, bool);
|
||||||
void DSQL_sql_info(Jrd::thread_db*, Jrd::dsql_req*,
|
void DSQL_sql_info(Jrd::thread_db*, Jrd::dsql_req*,
|
||||||
ULONG, const UCHAR*, ULONG, UCHAR*);
|
ULONG, const UCHAR*, ULONG, UCHAR*);
|
||||||
|
|
||||||
|
@ -452,6 +452,11 @@ interface Statement : ReferenceCounted
|
|||||||
PREPARE_PREFETCH_METADATA | PREPARE_PREFETCH_LEGACY_PLAN | PREPARE_PREFETCH_DETAILED_PLAN |
|
PREPARE_PREFETCH_METADATA | PREPARE_PREFETCH_LEGACY_PLAN | PREPARE_PREFETCH_DETAILED_PLAN |
|
||||||
PREPARE_PREFETCH_AFFECTED_RECORDS;
|
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.
|
// Statement flags.
|
||||||
const uint FLAG_HAS_CURSOR = 0x01;
|
const uint FLAG_HAS_CURSOR = 0x01;
|
||||||
const uint FLAG_REPEAT_EXECUTE = 0x02;
|
const uint FLAG_REPEAT_EXECUTE = 0x02;
|
||||||
|
@ -1718,6 +1718,7 @@ namespace Firebird
|
|||||||
static const unsigned PREPARE_PREFETCH_FLAGS = 0x40;
|
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_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_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_HAS_CURSOR = 0x1;
|
||||||
static const unsigned FLAG_REPEAT_EXECUTE = 0x2;
|
static const unsigned FLAG_REPEAT_EXECUTE = 0x2;
|
||||||
static const unsigned CURSOR_TYPE_SCROLLABLE = 0x1;
|
static const unsigned CURSOR_TYPE_SCROLLABLE = 0x1;
|
||||||
|
@ -478,6 +478,8 @@ enum info_db_provider
|
|||||||
#define isc_info_sql_stmt_timeout_user 28
|
#define isc_info_sql_stmt_timeout_user 28
|
||||||
#define isc_info_sql_stmt_timeout_run 29
|
#define isc_info_sql_stmt_timeout_run 29
|
||||||
#define isc_info_sql_stmt_blob_align 30
|
#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 */
|
/* SQL information return values */
|
||||||
|
@ -1457,6 +1457,7 @@ type
|
|||||||
const PREPARE_PREFETCH_FLAGS = Cardinal($40);
|
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_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_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_HAS_CURSOR = Cardinal($1);
|
||||||
const FLAG_REPEAT_EXECUTE = Cardinal($2);
|
const FLAG_REPEAT_EXECUTE = Cardinal($2);
|
||||||
const CURSOR_TYPE_SCROLLABLE = Cardinal($1);
|
const CURSOR_TYPE_SCROLLABLE = Cardinal($1);
|
||||||
|
@ -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 print_message(Firebird::IMessageMetadata* msg, const char* dir);
|
||||||
static void process_header(Firebird::IMessageMetadata*, const unsigned pad[], TEXT header[], TEXT header2[]);
|
static void process_header(Firebird::IMessageMetadata*, const unsigned pad[], TEXT header[], TEXT header2[]);
|
||||||
static void process_plan();
|
static void process_plan();
|
||||||
|
static void process_exec_path();
|
||||||
static SINT64 process_record_count(const unsigned statement_type);
|
static SINT64 process_record_count(const unsigned statement_type);
|
||||||
static unsigned process_message_display(Firebird::IMessageMetadata* msg, unsigned pad[]);
|
static unsigned process_message_display(Firebird::IMessageMetadata* msg, unsigned pad[]);
|
||||||
static processing_state process_statement(const TEXT*);
|
static processing_state process_statement(const TEXT*);
|
||||||
@ -457,6 +458,7 @@ public:
|
|||||||
Echo = false;
|
Echo = false;
|
||||||
Time_display = false;
|
Time_display = false;
|
||||||
Sqlda_display = false;
|
Sqlda_display = false;
|
||||||
|
ExecPathDisplay[0] = 0;
|
||||||
Stats = false;
|
Stats = false;
|
||||||
Autocommit = true; // Commit ddl
|
Autocommit = true; // Commit ddl
|
||||||
Warnings = true; // Print warnings
|
Warnings = true; // Print warnings
|
||||||
@ -480,6 +482,7 @@ public:
|
|||||||
bool Echo;
|
bool Echo;
|
||||||
bool Time_display;
|
bool Time_display;
|
||||||
bool Sqlda_display;
|
bool Sqlda_display;
|
||||||
|
UCHAR ExecPathDisplay[10];
|
||||||
bool Stats;
|
bool Stats;
|
||||||
bool Autocommit; // Commit ddl
|
bool Autocommit; // Commit ddl
|
||||||
bool Warnings; // Print warnings
|
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,
|
stat, count, list, plan, planonly, explain, blobdisplay, echo, autoddl,
|
||||||
width, transaction, terminator, names, time,
|
width, transaction, terminator, names, time,
|
||||||
//#ifdef DEV_BUILD
|
|
||||||
sqlda_display,
|
sqlda_display,
|
||||||
//#endif
|
exec_path_display,
|
||||||
sql, warning, sqlCont, heading, bail,
|
sql, warning, sqlCont, heading, bail,
|
||||||
bulk_insert, maxrows, stmtTimeout,
|
bulk_insert, maxrows, stmtTimeout,
|
||||||
keepTranParams,
|
keepTranParams,
|
||||||
@ -5201,9 +5203,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
|||||||
{SetOptions::terminator, "TERMINATOR", 4},
|
{SetOptions::terminator, "TERMINATOR", 4},
|
||||||
{SetOptions::names, "NAMES", 0},
|
{SetOptions::names, "NAMES", 0},
|
||||||
{SetOptions::time, "TIME", 0},
|
{SetOptions::time, "TIME", 0},
|
||||||
//#ifdef DEV_BUILD
|
|
||||||
{SetOptions::sqlda_display, "SQLDA_DISPLAY", 0},
|
{SetOptions::sqlda_display, "SQLDA_DISPLAY", 0},
|
||||||
//#endif
|
{SetOptions::exec_path_display, "EXEC_PATH_DISPLAY", 0},
|
||||||
{SetOptions::sql, "SQL", 0},
|
{SetOptions::sql, "SQL", 0},
|
||||||
{SetOptions::warning, "WARNINGS", 7},
|
{SetOptions::warning, "WARNINGS", 7},
|
||||||
{SetOptions::warning, "WNG", 0},
|
{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);
|
ret = do_set_command(parms[2], &setValues.Time_display);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//#ifdef DEV_BUILD
|
|
||||||
case SetOptions::sqlda_display:
|
case SetOptions::sqlda_display:
|
||||||
ret = do_set_command(parms[2], &setValues.Sqlda_display);
|
ret = do_set_command(parms[2], &setValues.Sqlda_display);
|
||||||
break;
|
break;
|
||||||
//#endif // DEV_BUILD
|
|
||||||
|
case SetOptions::exec_path_display:
|
||||||
|
ret = SKIP;
|
||||||
|
if (strcmp(parms[2], "OFF") == 0)
|
||||||
|
setValues.ExecPathDisplay[0] = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Firebird::Array<UCHAR> 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:
|
case SetOptions::sql:
|
||||||
if (!strcmp(parms[2], "DIALECT"))
|
if (!strcmp(parms[2], "DIALECT"))
|
||||||
@ -8366,6 +8408,58 @@ static void process_plan()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void process_exec_path()
|
||||||
|
{
|
||||||
|
if (!global_Stmt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Firebird::Array<UCHAR> 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
|
// 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,
|
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 (failed())
|
||||||
{
|
{
|
||||||
if (isqlGlob.SQL_dialect == SQL_DIALECT_V6_TRANSITION && Input_file)
|
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 =
|
const bool is_selectable =
|
||||||
statement_type == isc_info_sql_stmt_select ||
|
statement_type == isc_info_sql_stmt_select ||
|
||||||
statement_type == isc_info_sql_stmt_select_for_upd ||
|
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 the statement isn't a select, execute it and be done
|
||||||
|
|
||||||
if (!is_selectable && !setValues.Planonly)
|
if (!is_selectable && !setValues.Planonly)
|
||||||
|
@ -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) ?
|
const int dialect = isInternalRequest || (dbb.dbb_flags & DBB_DB_SQL_dialect_3) ?
|
||||||
SQL_DIALECT_V6 : SQL_DIALECT_V5;
|
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);
|
NULL, NULL, isInternalRequest);
|
||||||
|
|
||||||
const DsqlCompiledStatement* statement = request->getStatement();
|
const DsqlCompiledStatement* statement = request->getStatement();
|
||||||
|
@ -2646,7 +2646,7 @@ JRequest* JAttachment::compileRequest(CheckStatusWrapper* user_status,
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
jrd_req* request = NULL;
|
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();
|
stmt = request->getStatement();
|
||||||
|
|
||||||
trace.finish(request, ITracePlugin::RESULT_SUCCESS);
|
trace.finish(request, ITracePlugin::RESULT_SUCCESS);
|
||||||
@ -5444,7 +5444,7 @@ JStatement* JAttachment::prepare(CheckStatusWrapper* user_status, ITransaction*
|
|||||||
// observation for now.
|
// observation for now.
|
||||||
StatementMetadata::buildInfoItems(items, flags);
|
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);
|
&items, &buffer, false);
|
||||||
rc = FB_NEW JStatement(statement, getStable(), buffer);
|
rc = FB_NEW JStatement(statement, getStable(), buffer);
|
||||||
rc->addRef();
|
rc->addRef();
|
||||||
@ -9189,7 +9189,8 @@ void JRD_compile(thread_db* tdbb,
|
|||||||
RefStrPtr ref_str,
|
RefStrPtr ref_str,
|
||||||
ULONG dbginfo_length,
|
ULONG dbginfo_length,
|
||||||
const UCHAR* dbginfo,
|
const UCHAR* dbginfo,
|
||||||
bool isInternalRequest)
|
bool isInternalRequest,
|
||||||
|
bool preserveBlrData)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -9210,20 +9211,14 @@ void JRD_compile(thread_db* tdbb,
|
|||||||
|
|
||||||
JrdStatement* statement = request->getStatement();
|
JrdStatement* statement = request->getStatement();
|
||||||
|
|
||||||
if (!ref_str)
|
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
|
|
||||||
statement->sqlText = ref_str;
|
statement->sqlText = ref_str;
|
||||||
|
|
||||||
|
fb_assert(statement->blr.isEmpty());
|
||||||
|
|
||||||
|
if (preserveBlrData)
|
||||||
|
statement->blr.insert(0, blr, blr_length);
|
||||||
|
|
||||||
*req_handle = request;
|
*req_handle = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_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,
|
void JRD_compile(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, Jrd::jrd_req** req_handle,
|
||||||
ULONG blr_length, const UCHAR* blr, Firebird::RefStrPtr,
|
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&);
|
bool JRD_verify_database_access(const Firebird::PathName&);
|
||||||
void JRD_shutdown_attachment(Jrd::Attachment* attachment);
|
void JRD_shutdown_attachment(Jrd::Attachment* attachment);
|
||||||
void JRD_shutdown_attachments(Jrd::Database* dbb);
|
void JRD_shutdown_attachments(Jrd::Database* dbb);
|
||||||
|
Loading…
Reference in New Issue
Block a user