Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/README.isc_info_xxx
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,10 @@ New items for isc_transaction_info:

6. isc_info_tra_lock_timeout
return lock timeout of current transaction

New items for isc_dsql_sql_info:

1. isc_info_sql_exec_path_nodes
return execution nodes tree formatted as XML.
The response can be span over multiple chunks to exceed the response
length limit.
8 changes: 8 additions & 0 deletions doc/README.isql_enhancements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -540,3 +540,11 @@ CON> where true;
CONSTANT
============
1

16) SET EXEC_PATH_DISPLAY NODES

Retrieves the execution nodes tree of a DML statement formatted as XML.

It requires server v6 or greater to work.

SET EXEC_PATH_DISPLAY OFF disables both output of BLR and nodes tree.
6 changes: 5 additions & 1 deletion src/dsql/ExprNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,11 @@ void Printable::print(NodePrinter& printer) const
{
NodePrinter subPrinter(printer.getIndent() + 1);
Firebird::string tag(internalPrint(subPrinter));
printer.begin(tag);
Firebird::string attr;
#ifdef DEV_BUILD
attr.printf("addr=\"%p\"", this);
#endif
printer.begin(tag, attr.c_str());
printer.append(subPrinter);
printer.end();
}
Expand Down
7 changes: 6 additions & 1 deletion src/dsql/NodePrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,16 @@ class NodePrinter
}

public:
void begin(const Firebird::string& s)
void begin(const Firebird::string& s, const char* attributes = nullptr)
{
printIndent();
text += "<";
text += s;
if (attributes != nullptr)
{
text += ' ';
text += attributes;
}
text += ">\n";

++indent;
Expand Down
28 changes: 28 additions & 0 deletions src/dsql/dsql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,34 @@ static void sql_info(thread_db* tdbb,
}
break;

case isc_info_sql_exec_path_nodes:
if (const Statement* stmt = dsqlRequest->getStatement())
{
if (stmt->topNode)
{
NodePrinter printer;
stmt->topNode->print(printer);

const UCHAR* p = reinterpret_cast<const UCHAR*>(printer.getText().c_str());
ULONG length = printer.getText().size();

while (length)
{
ULONG bufferLength = end_info - info - 4;
ULONG maxLength = MIN(bufferLength, MAX_USHORT);
ULONG segmentLength = MIN(length, maxLength);

info = put_item(item, segmentLength, p, info, end_info);
if (!info)
return;

p += segmentLength;
length -= segmentLength;
}
}
}
break;

case isc_info_sql_num_variables:
case isc_info_sql_describe_vars:
if (messageFound)
Expand Down
1 change: 1 addition & 0 deletions src/include/firebird/impl/inf_pub.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ enum info_db_provider
#define isc_info_sql_exec_path_blr_bytes 31
#define isc_info_sql_exec_path_blr_text 32
#define isc_info_sql_relation_schema 33
#define isc_info_sql_exec_path_nodes 34

/*********************************/
/* SQL information return values */
Expand Down
1 change: 1 addition & 0 deletions src/include/firebird/impl/msg/isql.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,4 @@ FB_IMPL_MSG_SYMBOL(ISQL, 208, HLP_SETAUTOTERM, " SET AUTOTERM -- to
FB_IMPL_MSG_SYMBOL(ISQL, 209, HLP_SETWIRESTATS, " SET WIRE_stats -- toggle display of wire (network) statistics")
FB_IMPL_MSG_SYMBOL(ISQL, 210, USAGE_SEARCH_PATH, " -(se)arch_path <path> set schema search path")
FB_IMPL_MSG_SYMBOL(ISQL, 211, MSG_SCHEMAS, "Schemas:")
FB_IMPL_MSG_SYMBOL(ISQL, 212, HLP_SETEXECPATHDISPLAY, " SET EXEC_PATH_DISPLAY <BLR|NODES|OFF> -- toggle display of query execution path")
76 changes: 55 additions & 21 deletions src/isql/isql.epp
Original file line number Diff line number Diff line change
Expand Up @@ -503,14 +503,21 @@ static Firebird::GlobalPtr<string> TranParams;
class SetValues
{
public:
enum ExecPathOptions : unsigned
{
OFF = 0x00,
BLR = 0x01,
NODES = 0x02
};

SetValues()
{
//ColList global_Cols;
global_Col_default = 0; // Need to write code for it in the future.
Echo = false;
Time_display = false;
Sqlda_display = false;
ExecPathDisplay[0] = 0;
ExecPathDisplay = ExecPathOptions::OFF;
Stats = false;
Autocommit = true; // Commit ddl
Warnings = true; // Print warnings
Expand All @@ -537,7 +544,7 @@ public:
bool Echo;
bool Time_display;
bool Sqlda_display;
UCHAR ExecPathDisplay[10];
unsigned ExecPathDisplay;
bool Stats;
bool Autocommit; // Commit ddl
bool Warnings; // Print warnings
Expand Down Expand Up @@ -4750,13 +4757,13 @@ static processing_state execSetDebugCommand()
if (!DB)
return SKIP;

const char* stmt = setValues.ExecPathDisplay[0] ?
const char* stmt = setValues.ExecPathDisplay ?
"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))
if (setValues.ExecPathDisplay && (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
{
STDERROUT("SET EXEC_PATH_DISPLAY is not supported in this connection.");
return FAIL;
Expand Down Expand Up @@ -5015,17 +5022,17 @@ static processing_state frontend(const std::string& statement)
if (node.arg.empty())
return ps_ERR;
else if (node.arg == "OFF")
setValues.ExecPathDisplay[0] = 0;
else
setValues.ExecPathDisplay = SetValues::ExecPathOptions::OFF;
else if (node.arg == "BLR")
{
static constexpr UCHAR execPath[] = {isc_info_sql_exec_path_blr_text};

if (node.arg != "BLR")
return ps_ERR;

memcpy(setValues.ExecPathDisplay, execPath, FB_NELEM(execPath));
setValues.ExecPathDisplay[FB_NELEM(execPath)] = 0;
setValues.ExecPathDisplay |= SetValues::ExecPathOptions::BLR;
}
else if (node.arg == "NODES")
{
setValues.ExecPathDisplay |= SetValues::ExecPathOptions::NODES;
}
else
return ps_ERR;

return execSetDebugCommand();
},
Expand Down Expand Up @@ -5673,7 +5680,7 @@ void ISQL_get_version(bool call_by_create_db)
else
isqlGlob.db_SQL_dialect = SQL_DIALECT_V5;

if (setValues.ExecPathDisplay[0])
if (setValues.ExecPathDisplay)
execSetDebugCommand();
}

Expand Down Expand Up @@ -5825,6 +5832,24 @@ static processing_state print_sets()
print_set("Access Plan only:", setValues.Planonly);
print_set("Explain Access Plan:", setValues.ExplainPlan);

isqlGlob.printf("%-25s", "Execution path display:");
if (setValues.ExecPathDisplay == SetValues::ExecPathOptions::OFF)
{
isqlGlob.printf("OFF");
}
else
{
if (setValues.ExecPathDisplay & SetValues::ExecPathOptions::BLR)
{
isqlGlob.printf("BLR ");
}
if (setValues.ExecPathDisplay & SetValues::ExecPathOptions::NODES)
{
isqlGlob.printf("NODES");
}
}
isqlGlob.printf(NEWLINE);

isqlGlob.printf("%-25s", "Display BLOB type:");
switch (setValues.Doblob)
{
Expand Down Expand Up @@ -5942,6 +5967,7 @@ static processing_state help(const TEXT* what)
HLP_SETCOUNT, // SET COUNT -- toggle count of selected rows on/off
HLP_SETMAXROWS, // SET MAXROWS [<n>] -- toggle limit of selected rows to <n>, zero is no limit
HLP_SETECHO, // SET ECHO -- toggle command echo on/off
HLP_SETEXECPATHDISPLAY, // SET EXEC_PATH_DISPLAY <BLR|NODES|OFF> -- toggle display of query execution path
HLP_SETEXPLAIN, // SET EXPLAIN -- toggle display of query plan in the explained form
HLP_SETHEADING, // SET HEADING -- toggle column titles display on/off
HLP_SETKEEPTRAN, // SET KEEP_TRAN_params -- toggle to keep or not to keep text of following successful SET TRANSACTION statement
Expand Down Expand Up @@ -6377,7 +6403,7 @@ static processing_state newdb(const TEXT* dbname,
}
}

if (setValues.ExecPathDisplay[0])
if (setValues.ExecPathDisplay)
execSetDebugCommand();

global_Stmt = NULL;
Expand Down Expand Up @@ -8057,10 +8083,17 @@ static void process_exec_path()
return;

Firebird::Array<UCHAR> pathBuffer;
pathBuffer.getBuffer(MAX_USHORT, false);
// One megabyte is not too much
pathBuffer.getBuffer(1024 * 1024, false);

for (const UCHAR* code = setValues.ExecPathDisplay; *code; ++code)
static constexpr UCHAR execPath[] = { isc_info_sql_exec_path_blr_text, isc_info_sql_exec_path_nodes };

for (unsigned i = 0; i < std::size(execPath); ++i)
{
if ((setValues.ExecPathDisplay & (1 << i)) == 0)
continue;

const UCHAR* code = &execPath[i];
global_Stmt->getInfo(fbStatus, 1, code, pathBuffer.getCount(), pathBuffer.begin());

if (ISQL_errmsg(fbStatus))
Expand All @@ -8076,24 +8109,25 @@ static void process_exec_path()
{
const USHORT len = (USHORT) gds__vax_integer(ptr, sizeof(USHORT));
ptr += sizeof(USHORT);
pathString.assign((const char*) ptr, len);
pathString.append((const char*) ptr, len);
ptr += len;
}
else if (tag == isc_info_end)
break;
else if (tag == isc_info_truncated)
{
pathString = "* error: overflow *\n";
pathString += "* error: overflow *\n";
break;
}
else
pathString = "* unknown error *\n";
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" :
*code == isc_info_sql_exec_path_nodes ? "Nodes" :
"* unknown *"
),
NEWLINE, NEWLINE,
Expand Down Expand Up @@ -8538,7 +8572,7 @@ static processing_state process_statement(const std::string& str)
return ret; // do not execute
}

if (setValues.ExecPathDisplay[0])
if (setValues.ExecPathDisplay)
process_exec_path();

// If the statement isn't a select, execute it and be done
Expand Down
Loading