#include "ExplainTreeModelItem.h" #include "json/json.h" #include namespace { class registerMetaTypes { public: registerMetaTypes() { qRegisterMetaType(); } } registerMetaTypes_instance; ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan) { const auto json_null = Json::Value::nullSingleton(); ExplainTreeModelItemPtr result = std::make_shared(); result->nodeType = QString::fromStdString(plan.get("Node Type", json_null).asString()); result->parallelAware = plan.get("Parallel Aware", json_null).asBool(); result->strategy = QString::fromStdString(plan.get("Strategy", json_null).asString()); result->joinType = QString::fromStdString(plan.get("Join Type", json_null).asString()); result->startupCost = plan.get("Startup Cost", json_null).asFloat(); result->totalCost = plan.get("Total Cost", json_null).asFloat(); result->estimatedRows = plan.get("Plan Rows", json_null).asInt(); result->planWidth = plan.get("Plan Width", json_null).asInt(); result->actualStartupTime = plan.get("Actual Startup Time", json_null).asFloat(); result->actualTotalTime = plan.get("Actual Total Time", json_null).asFloat(); result->actualRows = plan.get("Actual Rows", json_null).asInt(); result->actualLoops = plan.get("Actual Loops", json_null).asInt(); result->relationName = QString::fromStdString(plan.get("Relation Name", json_null).asString()); result->alias = QString::fromStdString(plan.get("Alias", json_null).asString()); result->scanDirection = QString::fromStdString(plan.get("Scan Direction", json_null).asString()); result->indexName = QString::fromStdString(plan.get("Index Name", json_null).asString()); result->indexCondition = QString::fromStdString(plan.get("Index Cond", json_null).asString()); result->indexRecheck = QString::fromStdString(plan.get("Rows Removed by Index Recheck", json_null).asString()); result->filter = QString::fromStdString(plan.get("Filter", json_null).asString()); result->hashCondition = QString::fromStdString(plan.get("Hash Cond", json_null).asString()); result->sortKey = QString::fromStdString(plan.get("Sort Key", json_null).toStyledString()); result->sortMethod = QString::fromStdString(plan.get("Sort Method", json_null).asString()); result->sortSpaceUsed = plan.get("Sort Space Used", json_null).asInt(); result->sortSpaceType = QString::fromStdString(plan.get("Sort Space Type", json_null).asString()); result->sharedBlocks.hit = plan.get("Shared Hit Blocks", json_null).asInt(); result->sharedBlocks.read = plan.get("Shared Read Blocks", json_null).asInt(); result->sharedBlocks.dirtied = plan.get("Shared Dirtied Blocks", json_null).asInt(); result->sharedBlocks.written = plan.get("Shared Written Blocks", json_null).asInt(); result->localBlocks.hit = plan.get("Local Hit Blocks", json_null).asInt(); result->localBlocks.read = plan.get("Local Read Blocks", json_null).asInt(); result->localBlocks.dirtied = plan.get("Local Dirtied Blocks", json_null).asInt(); result->localBlocks.written = plan.get("Local Written Blocks", json_null).asInt(); result->tempBlocks.read = plan.get("Temp Read Blocks", json_null).asInt(); result->tempBlocks.written = plan.get("Temp Written Blocks", json_null).asInt(); result->ioTimes.read = plan.get("I/O Read Time", json_null).asDouble(); result->ioTimes.write = plan.get("I/O Write Time", json_null).asDouble(); Json::Value &plans = plan["Plans"]; if (plans.isArray()) { for (auto p : plans) { result->appendChild( createPlanItemFromJson(p)); } } // "Parallel Aware": false, return result; } } // END of unnamed namespace ExplainRoot::SPtr ExplainRoot::createFromJson(Json::Value &json) { auto res = std::make_shared(); // Explain always seems to be an array with one element if (json.isArray()) { if (!json.empty()) { Json::Value &explain = json[0]; Json::Value &plan = explain["Plan"]; res->plan = createPlanItemFromJson(plan); res->planningTime = explain["Planning Time"].asFloat(); res->executionTime = explain["Execution Time"].asFloat(); res->totalRuntime = explain["Total Runtime"].asFloat(); } } return res; } ExplainTreeModelItem::ExplainTreeModelItem() = default; ExplainTreeModelItem::~ExplainTreeModelItem() = default; void ExplainTreeModelItem::appendChild(const ItemPtr &child) { child->setParent(shared_from_this()); m_childItems.push_back(child); } ExplainTreeModelItemPtr ExplainTreeModelItem::child(int row) { return m_childItems.at(row); } int ExplainTreeModelItem::childCount() const { return static_cast(m_childItems.size()); } //int ExplainTreeModelItem::columnCount() const //{ // return 6; //} //QVariant ExplainTreeModelItem::data(int column) const //{ // QVariant r; // if (column == 0) { // r = nodeType; // } // else if (column == 1) { // } // return r; //} int ExplainTreeModelItem::row() const { int idx = 0; auto p = m_parentItem.lock(); if (p) { idx = std::find(p->m_childItems.begin(), p->m_childItems.end(), shared_from_this()) - p->m_childItems.begin(); } return idx; } void ExplainTreeModelItem::setParent(const ItemPtr &parent) { m_parentItem = parent; } ExplainTreeModelItemPtr ExplainTreeModelItem::parent() { auto p = m_parentItem.lock(); return p; } //void ExplainTreeModelItem::setNodeType(QString nt) //{ // m_nodeType = std::move(nt); //} //const QString& ExplainTreeModelItem::nodeType() const //{ // return m_nodeType; //} //void ExplainTreeModelItem::setParallelAware(bool aware) //{ // m_parallelAware = aware; //} //bool ExplainTreeModelItem::getParallelAware() const //{ // return m_parallelAware; //} //void ExplainTreeModelItem::setStrategy(QString strat) //{ // m_strategy = std::move(strat); //} //const QString& ExplainTreeModelItem::strategy() const //{ // return m_strategy; //} //void ExplainTreeModelItem::setJoinType(QString jointype) //{ // m_joinType = jointype; //} //QString ExplainTreeModelItem::joinType() const //{ // return m_joinType; //} //void ExplainTreeModelItem::setStartupCost(float cost) //{ // m_startupCost = cost; //} //void ExplainTreeModelItem::setTotalCost(float cost) //{ // m_totalCost = cost; //} //void ExplainTreeModelItem::setEstimatedRows(long long estimated) //{ // m_estimatedRows = estimated; //} //long long ExplainTreeModelItem::estimatedRows() const //{ // return m_estimatedRows; //} //void ExplainTreeModelItem::setPlanWidth(int width) //{ // m_planWidth = width; //} //void ExplainTreeModelItem::setActualStartupTime(float timems) //{ // m_actualStartupTime = timems; //} //void ExplainTreeModelItem::setActualTotalTime(float timems) //{ // m_actualTotalTime = timems; //} //float ExplainTreeModelItem::actualTotalTime() const //{ // return m_actualTotalTime; //} //void ExplainTreeModelItem::setActualRows(long long rowcount) //{ // m_actualRows = rowcount; //} //long long ExplainTreeModelItem::actualRows() const //{ // return m_actualRows; //} //void ExplainTreeModelItem::setActualLoops(int loopcount) //{ // m_actualLoops = loopcount; //} //int ExplainTreeModelItem::actualLoops() const //{ // return m_actualLoops; //} //void ExplainTreeModelItem::setRelationName(QString n) //{ // m_relationName = std::move(n); //} //void ExplainTreeModelItem::setAlias(QString a) //{ // m_alias = std::move(a); //} //void ExplainTreeModelItem::setScanDirection(QString dir) //{ // m_scanDirection = std::move(dir); //} //void ExplainTreeModelItem::setIndexName(QString idxname) //{ // m_indexName = std::move(idxname); //} //void ExplainTreeModelItem::setIndexCondition(QString idxcond) //{ // m_indexCondition = std::move(idxcond); //} //void ExplainTreeModelItem::setIndexRecheck(QString idxrecheck) //{ // m_indexRecheck = std::move(idxrecheck); //} //void ExplainTreeModelItem::setFilter(QString filter) //{ // m_filter = std::move(filter); //} //void ExplainTreeModelItem::setHashCondition(QString condition) //{ // m_hashCondition = std::move(condition); //} //void ExplainTreeModelItem::setSortKey(QString key) //{ // m_sortKey = std::move(key); //} //void ExplainTreeModelItem::setSortMethod(QString method) //{ // m_sortMethod = std::move(method); //} //void ExplainTreeModelItem::setSortSpaceUsed(int space) //{ // m_sortSpaceUsed = space; //} //void ExplainTreeModelItem::setSortSpaceType(QString type) //{ // m_sortSpaceType = std::move(type); //} float ExplainTreeModelItem::exclusiveTime() const { float tt = inclusiveTime(); for (auto&& c : m_childItems) { tt -= c->inclusiveTime(); } return tt; } float ExplainTreeModelItem::inclusiveTime() const { float t = actualTotalTime * actualLoops; return t; } float ExplainTreeModelItem::estimateError() const { float res = 1.0; if (estimatedRows > actualRows) { if (actualRows > 0) { res = float(estimatedRows) / actualRows; } else { res = std::numeric_limits::infinity(); } } else if (actualRows > estimatedRows) { if (estimatedRows > 0) { res = float(actualRows) / estimatedRows; } else { res = std::numeric_limits::infinity(); } res = -res; } return res; } QString ExplainTreeModelItem::detailString() const { QString s; if (!joinType.isEmpty()) { s += joinType + " " + nodeType + " "; } if (!strategy.isEmpty()) { s += strategy + " " + nodeType + " "; } if (!indexName.isEmpty()) { s+= scanDirection + " " + nodeType + "\n"; if (!indexCondition.isEmpty()) { s += "cond: " + indexCondition + " "; } if (!filter.isEmpty()) { s += "filter: " + filter + "\n"; } if (!indexRecheck.isEmpty()) { s += "removed by recheck: " + indexRecheck + "\n"; } s += "idx: " + indexName + " rel: " + alias + " "; } else { if (!alias.isEmpty()) { s += nodeType + " rel: " + alias + " "; } } if (!hashCondition.isEmpty()) { s += hashCondition + " "; } if (!sortMethod.isEmpty()) { s += sortMethod + " " + sortSpaceType + " " + QString::number(sortSpaceUsed) + "kB " + sortKey + " "; } return s.trimmed(); } //"Sort Key": ["pg_attribute.attname"], //"Sort Method": "quicksort", //"Sort Space Used": 1426, //"Sort Space Type": "Memory", //{ // "Node Type": "Index Scan", // "Parent Relationship": "Inner", // "Scan Direction": "Forward", // "Index Name": "pg_type_oid_index", // "Relation Name": "pg_type", // "Alias": "pg_type", // "Startup Cost": 0.15, // "Total Cost": 0.18, // "Plan Rows": 1, // "Plan Width": 758, // "Actual Startup Time": 0.003, // "Actual Total Time": 0.004, // "Actual Rows": 1, // "Actual Loops": 100, // "Index Cond": "(oid = pg_attribute.atttypid)", // "Rows Removed by Index Recheck": 0 // "Filter": "actief" //}