Messy commit. Testing suff and some improvements to how data is shown.
409
core/ExplainTreeModelItem.cpp
Normal file
|
|
@ -0,0 +1,409 @@
|
||||||
|
#include "ExplainTreeModelItem.h"
|
||||||
|
#include "json/json.h"
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan)
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto json_null = Json::Value::nullSingleton();
|
||||||
|
ExplainTreeModelItemPtr result = std::make_shared<ExplainTreeModelItem>();
|
||||||
|
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<ExplainRoot>();
|
||||||
|
// Explain always seems to be an array with one element
|
||||||
|
if (json.isArray()) {
|
||||||
|
if (json.size() > 0) {
|
||||||
|
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(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 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(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<float>::infinity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (actualRows > estimatedRows) {
|
||||||
|
if (estimatedRows > 0) {
|
||||||
|
res = float(actualRows) / estimatedRows;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = std::numeric_limits<float>::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"
|
||||||
|
//}
|
||||||
163
core/ExplainTreeModelItem.h
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
//#include <QVariant>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
class Value;
|
||||||
|
|
||||||
|
}
|
||||||
|
class ExplainTreeModelItem;
|
||||||
|
typedef std::shared_ptr<ExplainTreeModelItem> ExplainTreeModelItemPtr;
|
||||||
|
|
||||||
|
/* Columns for tree
|
||||||
|
* 0. explain text
|
||||||
|
* 1. exclusive times
|
||||||
|
* 2. inclusive
|
||||||
|
* 3. rows x
|
||||||
|
* 4. rows
|
||||||
|
* 5. loops
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \brief Class for the nodes in the QueryExplainModel
|
||||||
|
*/
|
||||||
|
class ExplainTreeModelItem: public std::enable_shared_from_this<ExplainTreeModelItem> {
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<ExplainTreeModelItem> ItemPtr;
|
||||||
|
|
||||||
|
struct Buffer {
|
||||||
|
int hit = 0;
|
||||||
|
int read = 0;
|
||||||
|
int dirtied = 0;
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
QString asString() const
|
||||||
|
{
|
||||||
|
return QString::asprintf("h %d/r %d/d %d/w %d", hit, read, dirtied, written);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TempBlocks {
|
||||||
|
int read = 0;
|
||||||
|
int written = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IoTimes {
|
||||||
|
double read = 0.0;
|
||||||
|
double write =0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExplainTreeModelItem();
|
||||||
|
~ExplainTreeModelItem();
|
||||||
|
|
||||||
|
ExplainTreeModelItem(const ExplainTreeModelItem &rhs) = delete;
|
||||||
|
ExplainTreeModelItem &operator=(const ExplainTreeModelItem &rhs) = delete;
|
||||||
|
|
||||||
|
void appendChild(ItemPtr child);
|
||||||
|
|
||||||
|
ExplainTreeModelItemPtr child(int row);
|
||||||
|
int childCount() const;
|
||||||
|
// int columnCount() const;
|
||||||
|
// QVariant data(int column) const;
|
||||||
|
int row() const;
|
||||||
|
void setParent(ItemPtr parent);
|
||||||
|
ItemPtr parent();
|
||||||
|
|
||||||
|
|
||||||
|
// void setNodeType(QString nt);
|
||||||
|
// const QString& nodeType() const;
|
||||||
|
// void setParallelAware(bool aware);
|
||||||
|
// bool getParallelAware() const;
|
||||||
|
// void setStrategy(QString strat);
|
||||||
|
// const QString& strategy() const;
|
||||||
|
// void setJoinType(QString jointype);
|
||||||
|
// QString joinType() const;
|
||||||
|
// void setStartupCost(float cost);
|
||||||
|
// void setTotalCost(float cost);
|
||||||
|
// void setEstimatedRows(long long estimated);
|
||||||
|
// long long estimatedRows() const;
|
||||||
|
// void setPlanWidth(int width);
|
||||||
|
// void setActualStartupTime(float timems);
|
||||||
|
// void setActualTotalTime(float timems);
|
||||||
|
// float actualTotalTime() const;
|
||||||
|
// void setActualRows(long long rowcount);
|
||||||
|
// long long actualRows() const;
|
||||||
|
// void setActualLoops(int loopcount);
|
||||||
|
// int actualLoops() const;
|
||||||
|
|
||||||
|
// void setRelationName(QString n);
|
||||||
|
// void setAlias(QString a);
|
||||||
|
// void setScanDirection(QString dir);
|
||||||
|
// void setIndexName(QString idxname);
|
||||||
|
// void setIndexCondition(QString idxcond);
|
||||||
|
// void setIndexRecheck(QString idxrecheck);
|
||||||
|
// void setFilter(QString filter);
|
||||||
|
// void setHashCondition(QString condition);
|
||||||
|
// void setSortKey(QString key);
|
||||||
|
// void setSortMethod(QString method);
|
||||||
|
// void setSortSpaceUsed(int space);
|
||||||
|
// void setSortSpaceType(QString type);
|
||||||
|
|
||||||
|
/** ActualTotalTime minus the actual total time of it's children */
|
||||||
|
float exclusiveTime() const;
|
||||||
|
float inclusiveTime() const;
|
||||||
|
float estimateError() const;
|
||||||
|
QString detailString() const;
|
||||||
|
|
||||||
|
//private:
|
||||||
|
std::vector<ItemPtr> m_childItems;
|
||||||
|
std::weak_ptr<ExplainTreeModelItem> m_parentItem;
|
||||||
|
|
||||||
|
QString nodeType;
|
||||||
|
bool parallelAware; // 9.6
|
||||||
|
QString strategy;
|
||||||
|
QString joinType;
|
||||||
|
float startupCost = 0.f;
|
||||||
|
float totalCost = 0.f;
|
||||||
|
int64_t estimatedRows = 0;
|
||||||
|
int planWidth = 0;
|
||||||
|
float actualStartupTime = 0.f;
|
||||||
|
float actualTotalTime = 0.f;
|
||||||
|
int64_t actualRows = 0;
|
||||||
|
int actualLoops = 0;
|
||||||
|
|
||||||
|
QString relationName;
|
||||||
|
QString alias;
|
||||||
|
QString scanDirection;
|
||||||
|
QString indexName;
|
||||||
|
QString indexCondition;
|
||||||
|
QString indexRecheck;
|
||||||
|
QString filter;
|
||||||
|
QString hashCondition;
|
||||||
|
QString sortKey;
|
||||||
|
QString sortMethod;
|
||||||
|
int sortSpaceUsed = -1;
|
||||||
|
QString sortSpaceType;
|
||||||
|
|
||||||
|
// Buffering related
|
||||||
|
Buffer sharedBlocks;
|
||||||
|
Buffer localBlocks;
|
||||||
|
TempBlocks tempBlocks;
|
||||||
|
IoTimes ioTimes;
|
||||||
|
|
||||||
|
// "Triggers": [
|
||||||
|
// ],
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExplainRoot {
|
||||||
|
public:
|
||||||
|
using SPtr = std::shared_ptr<ExplainRoot>;
|
||||||
|
static SPtr createFromJson(Json::Value &json);
|
||||||
|
|
||||||
|
ExplainTreeModelItemPtr plan;
|
||||||
|
float planningTime = 0.f;
|
||||||
|
// Triggers???
|
||||||
|
float executionTime = 0.f;
|
||||||
|
float totalRuntime = 0.f;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -31,7 +31,9 @@ SOURCES += my_boost_assert_handler.cpp \
|
||||||
PasswordManager.cpp \
|
PasswordManager.cpp \
|
||||||
CsvWriter.cpp \
|
CsvWriter.cpp \
|
||||||
BackupFormatModel.cpp \
|
BackupFormatModel.cpp \
|
||||||
QueuedBackgroundTask.cpp
|
QueuedBackgroundTask.cpp \
|
||||||
|
ExplainTreeModelItem.cpp \
|
||||||
|
jsoncpp.cpp
|
||||||
|
|
||||||
HEADERS += PasswordManager.h \
|
HEADERS += PasswordManager.h \
|
||||||
SqlLexer.h \
|
SqlLexer.h \
|
||||||
|
|
@ -39,9 +41,12 @@ HEADERS += PasswordManager.h \
|
||||||
CsvWriter.h \
|
CsvWriter.h \
|
||||||
BackupFormatModel.h \
|
BackupFormatModel.h \
|
||||||
QueuedBackgroundTask.h \
|
QueuedBackgroundTask.h \
|
||||||
Expected.h
|
Expected.h \
|
||||||
|
ExplainTreeModelItem.h
|
||||||
|
|
||||||
unix {
|
unix {
|
||||||
target.path = /usr/lib
|
target.path = /usr/lib
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
36
pglab/BaseTableModel.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include "BaseTableModel.h"
|
||||||
|
#include "ResultTableModelUtil.h"
|
||||||
|
#include <QBrush>
|
||||||
|
|
||||||
|
using namespace Pgsql;
|
||||||
|
|
||||||
|
BaseTableModel::BaseTableModel(QObject *parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QVariant BaseTableModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
Oid oid = getType(index.column());
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
v = getData(index);
|
||||||
|
if (oid == BOOLOID) {
|
||||||
|
v = FormatBoolForDisplay(v.toBool());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (role == Qt::TextAlignmentRole) {
|
||||||
|
v = GetDefaultAlignmentForType(oid);
|
||||||
|
}
|
||||||
|
else if (role == Qt::ForegroundRole) {
|
||||||
|
if (oid == BOOLOID) {
|
||||||
|
QVariant d = getData(index);
|
||||||
|
if (d.type() == QVariant::Bool) {
|
||||||
|
v = QBrush(GetDefaultBoolColor(d.toBool()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = QBrush(GetDefaultColorForType(oid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
21
pglab/BaseTableModel.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef BASETABLEMODEL_H
|
||||||
|
#define BASETABLEMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include "Pgsql_declare.h"
|
||||||
|
|
||||||
|
class BaseTableModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BaseTableModel(QObject *parent);
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual Oid getType(int column) const = 0;
|
||||||
|
virtual QVariant getData(const QModelIndex &index) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BASETABLEMODEL_H
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
#include "DatabasesTableModel.h"
|
#include "DatabasesTableModel.h"
|
||||||
#include "PgDatabaseCatalogue.h"
|
#include "PgDatabaseCatalogue.h"
|
||||||
#include "PgDatabaseContainer.h"
|
#include "PgDatabaseContainer.h"
|
||||||
#include "PgAuthIdContainer.h"
|
#include "PgAuthIdContainer.h"
|
||||||
|
#include "ResultTableModelUtil.h"
|
||||||
|
|
||||||
|
using namespace Pgsql;
|
||||||
|
|
||||||
DatabasesTableModel::DatabasesTableModel(QObject *parent)
|
DatabasesTableModel::DatabasesTableModel(QObject *parent)
|
||||||
: QAbstractTableModel(parent)
|
: BaseTableModel(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,7 +62,7 @@ QVariant DatabasesTableModel::headerData(int section, Qt::Orientation orientatio
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DatabasesTableModel::rowCount(const QModelIndex &parent) const
|
int DatabasesTableModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (m_databases) {
|
if (m_databases) {
|
||||||
|
|
@ -68,62 +71,79 @@ int DatabasesTableModel::rowCount(const QModelIndex &parent) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DatabasesTableModel::columnCount(const QModelIndex &parent) const
|
int DatabasesTableModel::columnCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
int result = 10;
|
int result = COL_COUNT;
|
||||||
// if (parent.isValid())
|
|
||||||
// return 10;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant DatabasesTableModel::data(const QModelIndex &index, int role) const
|
Oid DatabasesTableModel::getType(int column) const
|
||||||
|
{
|
||||||
|
Oid oid;
|
||||||
|
switch (column) {
|
||||||
|
case AllowConnCol:
|
||||||
|
case IsTemplateCol:
|
||||||
|
oid = BOOLOID;
|
||||||
|
break;
|
||||||
|
case ConnLimitCol:
|
||||||
|
oid = INT4OID;
|
||||||
|
break;
|
||||||
|
case AclCol:
|
||||||
|
case CollateCol:
|
||||||
|
case CTypeCol:
|
||||||
|
case EncodingCol:
|
||||||
|
case DbaCol:
|
||||||
|
case NameCol:
|
||||||
|
case TablespaceCol:
|
||||||
|
oid = VARCHAROID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
oid = InvalidOid;
|
||||||
|
}
|
||||||
|
return oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DatabasesTableModel::getData(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
QVariant v;
|
QVariant v;
|
||||||
//if (!index.isValid())
|
//if (!index.isValid())
|
||||||
if (m_databases) {
|
if (m_databases) {
|
||||||
const PgDatabase &db = m_databases->getByIdx(index.row());
|
const PgDatabase &db = m_databases->getByIdx(index.row());
|
||||||
if (role == Qt::DisplayRole) {
|
switch (index.column()) {
|
||||||
switch (index.column()) {
|
case NameCol:
|
||||||
case NameCol:
|
v = db.name;
|
||||||
v = db.name;
|
break;
|
||||||
break;
|
case DbaCol:
|
||||||
case DbaCol:
|
v = getRoleDisplayString(m_catalog, db.dba);
|
||||||
// todo lookup role name
|
break;
|
||||||
{
|
case EncodingCol:
|
||||||
const auto& roles = m_catalog->authIds();
|
// todo lookup encoding name
|
||||||
v = QString("%1 (%2)").arg(roles->getByOid(db.dba).name).arg(db.dba);
|
v = db.encoding;
|
||||||
}
|
break;
|
||||||
break;
|
case CollateCol:
|
||||||
case EncodingCol:
|
v = db.collate;
|
||||||
// todo lookup encoding name
|
break;
|
||||||
v = db.encoding;
|
case CTypeCol:
|
||||||
break;
|
v = db.ctype;
|
||||||
case CollateCol:
|
break;
|
||||||
v = db.collate;
|
case IsTemplateCol:
|
||||||
break;
|
v = db.isTemplate;
|
||||||
case CTypeCol:
|
break;
|
||||||
v = db.ctype;
|
case AllowConnCol:
|
||||||
break;
|
v = db.allowConn;
|
||||||
case IsTemplateCol:
|
break;
|
||||||
v = db.isTemplate;
|
case ConnLimitCol:
|
||||||
break;
|
v = db.connLimit;
|
||||||
case AllowConnCol:
|
break;
|
||||||
v = db.allowConn;
|
case TablespaceCol:
|
||||||
break;
|
// todo lookup tablespace name
|
||||||
case ConnLimitCol:
|
v = db.tablespace;
|
||||||
v = db.connLimit;
|
break;
|
||||||
break;
|
case AclCol:
|
||||||
case TablespaceCol:
|
v = db.acl;
|
||||||
// todo lookup tablespace name
|
break;
|
||||||
v = db.tablespace;
|
|
||||||
break;
|
|
||||||
case AclCol:
|
|
||||||
v = db.acl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef DATABASESTABLEMODEL_H
|
#ifndef DATABASESTABLEMODEL_H
|
||||||
#define DATABASESTABLEMODEL_H
|
#define DATABASESTABLEMODEL_H
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include "BaseTableModel.h"
|
||||||
|
|
||||||
class PgDatabaseContainer;
|
class PgDatabaseContainer;
|
||||||
class PgDatabaseCatalogue;
|
class PgDatabaseCatalogue;
|
||||||
|
|
@ -9,14 +9,14 @@ class PgDatabaseCatalogue;
|
||||||
/** Class for displaying the list of databases of a server in a QTableView
|
/** Class for displaying the list of databases of a server in a QTableView
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class DatabasesTableModel : public QAbstractTableModel
|
class DatabasesTableModel : public BaseTableModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum e_Columns : int { NameCol, DbaCol, EncodingCol, CollateCol,
|
enum e_Columns : int { NameCol, DbaCol, EncodingCol, CollateCol,
|
||||||
CTypeCol, IsTemplateCol, AllowConnCol, ConnLimitCol,
|
CTypeCol, IsTemplateCol, AllowConnCol, ConnLimitCol,
|
||||||
TablespaceCol, AclCol };
|
TablespaceCol, AclCol, COL_COUNT };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -31,7 +31,10 @@ public:
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual Oid getType(int column) const override;
|
||||||
|
virtual QVariant getData(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
// QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PgDatabaseCatalogue *m_catalog = nullptr;
|
const PgDatabaseCatalogue *m_catalog = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -1,384 +0,0 @@
|
||||||
#include "ExplainTreeModelItem.h"
|
|
||||||
#include "json/json.h"
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan)
|
|
||||||
{
|
|
||||||
ExplainTreeModelItemPtr result = std::make_shared<ExplainTreeModelItem>();
|
|
||||||
result->setNodeType(QString::fromStdString(plan["Node Type"].asString()));
|
|
||||||
result->setStrategy(QString::fromStdString(plan["Strategy"].asString()));
|
|
||||||
result->setJoinType(QString::fromStdString(plan["Join Type"].asString()));
|
|
||||||
result->setStartupCost(plan["Startup Cost"].asFloat());
|
|
||||||
result->setTotalCost(plan["Total Cost"].asFloat());
|
|
||||||
result->setEstimatedRows(plan["Plan Rows"].asInt());
|
|
||||||
result->setPlanWidth(plan["Plan Width"].asInt());
|
|
||||||
result->setActualStartupTime(plan["Actual Startup Time"].asFloat());
|
|
||||||
result->setActualTotalTime(plan["Actual Total Time"].asFloat());
|
|
||||||
result->setActualRows(plan["Actual Rows"].asInt());
|
|
||||||
result->setActualLoops(plan["Actual Loops"].asInt());
|
|
||||||
|
|
||||||
result->setRelationName(QString::fromStdString(plan["Relation Name"].asString()));
|
|
||||||
result->setAlias(QString::fromStdString(plan["Alias"].asString()));
|
|
||||||
result->setScanDirection(QString::fromStdString(plan["Scan Direction"].asString()));
|
|
||||||
result->setIndexName(QString::fromStdString(plan["Index Name"].asString()));
|
|
||||||
result->setIndexCondition(QString::fromStdString(plan["Index Cond"].asString()));
|
|
||||||
result->setIndexRecheck(QString::fromStdString(plan["Rows Removed by Index Recheck"].asString()));
|
|
||||||
result->setFilter(QString::fromStdString(plan["Filter"].asString()));
|
|
||||||
result->setHashCondition(QString::fromStdString(plan["Hash Cond"].asString()));
|
|
||||||
|
|
||||||
result->setSortKey(QString::fromStdString(plan["Sort Key"].toStyledString()));
|
|
||||||
result->setSortMethod(QString::fromStdString(plan["Sort Method"].asString()));
|
|
||||||
if (plan.isMember("Sort Space Used")) {
|
|
||||||
const Json::Value& sm = plan["Sort Space Used"];
|
|
||||||
if (sm.isInt()) {
|
|
||||||
result->setSortSpaceUsed(sm.asInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result->setSortSpaceType(QString::fromStdString(plan["Sort Space Type"].asString()));
|
|
||||||
|
|
||||||
|
|
||||||
Json::Value &plans = plan["Plans"];
|
|
||||||
if (plans.isArray()) {
|
|
||||||
for (auto p : plans) {
|
|
||||||
result->appendChild(
|
|
||||||
createPlanItemFromJson(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // END of unnamed namespace
|
|
||||||
|
|
||||||
ExplainRoot::SPtr ExplainRoot::createFromJson(Json::Value &json)
|
|
||||||
{
|
|
||||||
auto res = std::make_shared<ExplainRoot>();
|
|
||||||
// Explain always seems to be an array with one element
|
|
||||||
if (json.isArray()) {
|
|
||||||
if (json.size() > 0) {
|
|
||||||
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(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 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(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::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 = m_actualTotalTime * m_actualLoops;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ExplainTreeModelItem::estimateError() const
|
|
||||||
{
|
|
||||||
float res = 1.0;
|
|
||||||
if (m_estimatedRows > m_actualRows) {
|
|
||||||
if (m_actualRows > 0) {
|
|
||||||
res = float(m_estimatedRows) / m_actualRows;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res = std::numeric_limits<float>::infinity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_actualRows > m_estimatedRows) {
|
|
||||||
if (m_estimatedRows > 0) {
|
|
||||||
res = float(m_actualRows) / m_estimatedRows;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res = std::numeric_limits<float>::infinity();
|
|
||||||
}
|
|
||||||
res = -res;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ExplainTreeModelItem::detailString() const
|
|
||||||
{
|
|
||||||
QString s;
|
|
||||||
if (!m_joinType.isEmpty()) {
|
|
||||||
s += m_joinType + " " + m_nodeType + " ";
|
|
||||||
}
|
|
||||||
if (!m_strategy.isEmpty()) {
|
|
||||||
s += m_strategy + " " + m_nodeType + " ";
|
|
||||||
}
|
|
||||||
if (!m_indexName.isEmpty()) {
|
|
||||||
s+= m_scanDirection + " "
|
|
||||||
+ m_nodeType + "\n";
|
|
||||||
if (!m_indexCondition.isEmpty()) {
|
|
||||||
s += "cond: " + m_indexCondition + " ";
|
|
||||||
}
|
|
||||||
if (!m_filter.isEmpty()) {
|
|
||||||
s += "filter: " + m_filter + "\n";
|
|
||||||
}
|
|
||||||
if (!m_indexRecheck.isEmpty()) {
|
|
||||||
s += "removed by recheck: " + m_indexRecheck + "\n";
|
|
||||||
}
|
|
||||||
s += "idx: " + m_indexName + " rel: " + m_alias + " ";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!m_alias.isEmpty()) {
|
|
||||||
s += m_nodeType + " rel: " + m_alias + " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_hashCondition.isEmpty()) {
|
|
||||||
s += m_hashCondition + " ";
|
|
||||||
}
|
|
||||||
if (!m_sortMethod.isEmpty()) {
|
|
||||||
s += m_sortMethod + " " + m_sortSpaceType + " "
|
|
||||||
+ QString::number(m_sortSpaceUsed) + "kB "
|
|
||||||
+ m_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"
|
|
||||||
//}
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QList>
|
|
||||||
//#include <QVariant>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace Json {
|
|
||||||
|
|
||||||
class Value;
|
|
||||||
|
|
||||||
}
|
|
||||||
class ExplainTreeModelItem;
|
|
||||||
typedef std::shared_ptr<ExplainTreeModelItem> ExplainTreeModelItemPtr;
|
|
||||||
|
|
||||||
/* Columns for tree
|
|
||||||
* 0. explain text
|
|
||||||
* 1. exclusive times
|
|
||||||
* 2. inclusive
|
|
||||||
* 3. rows x
|
|
||||||
* 4. rows
|
|
||||||
* 5. loops
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \brief Class for the nodes in the QueryExplainModel
|
|
||||||
*/
|
|
||||||
class ExplainTreeModelItem: public std::enable_shared_from_this<ExplainTreeModelItem> {
|
|
||||||
public:
|
|
||||||
typedef std::shared_ptr<ExplainTreeModelItem> ItemPtr;
|
|
||||||
|
|
||||||
|
|
||||||
ExplainTreeModelItem();
|
|
||||||
~ExplainTreeModelItem();
|
|
||||||
|
|
||||||
ExplainTreeModelItem(const ExplainTreeModelItem &rhs) = delete;
|
|
||||||
ExplainTreeModelItem &operator=(const ExplainTreeModelItem &rhs) = delete;
|
|
||||||
|
|
||||||
void appendChild(ItemPtr child);
|
|
||||||
|
|
||||||
ExplainTreeModelItemPtr child(int row);
|
|
||||||
int childCount() const;
|
|
||||||
// int columnCount() const;
|
|
||||||
// QVariant data(int column) const;
|
|
||||||
int row() const;
|
|
||||||
void setParent(ItemPtr parent);
|
|
||||||
ItemPtr parent();
|
|
||||||
|
|
||||||
|
|
||||||
void setNodeType(QString nt);
|
|
||||||
const QString& nodeType() const;
|
|
||||||
void setStrategy(QString strat);
|
|
||||||
const QString& strategy() const;
|
|
||||||
void setJoinType(QString jointype);
|
|
||||||
QString joinType() const;
|
|
||||||
void setStartupCost(float cost);
|
|
||||||
void setTotalCost(float cost);
|
|
||||||
void setEstimatedRows(long long estimated);
|
|
||||||
long long estimatedRows() const;
|
|
||||||
void setPlanWidth(int width);
|
|
||||||
void setActualStartupTime(float timems);
|
|
||||||
void setActualTotalTime(float timems);
|
|
||||||
float actualTotalTime() const;
|
|
||||||
void setActualRows(long long rowcount);
|
|
||||||
long long actualRows() const;
|
|
||||||
void setActualLoops(int loopcount);
|
|
||||||
int actualLoops() const;
|
|
||||||
|
|
||||||
void setRelationName(QString n);
|
|
||||||
void setAlias(QString a);
|
|
||||||
void setScanDirection(QString dir);
|
|
||||||
void setIndexName(QString idxname);
|
|
||||||
void setIndexCondition(QString idxcond);
|
|
||||||
void setIndexRecheck(QString idxrecheck);
|
|
||||||
void setFilter(QString filter);
|
|
||||||
void setHashCondition(QString condition);
|
|
||||||
void setSortKey(QString key);
|
|
||||||
void setSortMethod(QString method);
|
|
||||||
void setSortSpaceUsed(int space);
|
|
||||||
void setSortSpaceType(QString type);
|
|
||||||
|
|
||||||
/** ActualTotalTime minus the actual total time of it's children */
|
|
||||||
float exclusiveTime() const;
|
|
||||||
float inclusiveTime() const;
|
|
||||||
float estimateError() const;
|
|
||||||
QString detailString() const;
|
|
||||||
private:
|
|
||||||
std::vector<ItemPtr> m_childItems;
|
|
||||||
std::weak_ptr<ExplainTreeModelItem> m_parentItem;
|
|
||||||
|
|
||||||
QString m_nodeType;
|
|
||||||
QString m_strategy;
|
|
||||||
QString m_joinType;
|
|
||||||
float m_startupCost = 0.f;
|
|
||||||
float m_totalCost = 0.f;
|
|
||||||
long long m_estimatedRows = 0;
|
|
||||||
int m_planWidth = 0;
|
|
||||||
float m_actualStartupTime = 0.f;
|
|
||||||
float m_actualTotalTime = 0.f;
|
|
||||||
long long m_actualRows = 0;
|
|
||||||
int m_actualLoops = 0;
|
|
||||||
|
|
||||||
QString m_relationName;
|
|
||||||
QString m_alias;
|
|
||||||
QString m_scanDirection;
|
|
||||||
QString m_indexName;
|
|
||||||
QString m_indexCondition;
|
|
||||||
QString m_indexRecheck;
|
|
||||||
QString m_filter;
|
|
||||||
QString m_hashCondition;
|
|
||||||
QString m_sortKey;
|
|
||||||
QString m_sortMethod;
|
|
||||||
int m_sortSpaceUsed = -1;
|
|
||||||
QString m_sortSpaceType;
|
|
||||||
|
|
||||||
// "Output": ["f1.id", "f1.program", "f1.version", "f1.lic_number", "f1.callstack_crc_1", "f1.callstack_crc_2", "array_agg(f2.id)"],
|
|
||||||
// "Group Key": ["f1.id"],
|
|
||||||
// "Shared Hit Blocks": 694427,
|
|
||||||
// "Shared Read Blocks": 0,
|
|
||||||
// "Shared Dirtied Blocks": 0,
|
|
||||||
// "Shared Written Blocks": 0,
|
|
||||||
// "Local Hit Blocks": 0,
|
|
||||||
// "Local Read Blocks": 0,
|
|
||||||
// "Local Dirtied Blocks": 0,
|
|
||||||
// "Local Written Blocks": 0,
|
|
||||||
// "Temp Read Blocks": 0,
|
|
||||||
// "Temp Written Blocks": 0
|
|
||||||
|
|
||||||
// "Parent Relationship": "Outer",
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExplainRoot {
|
|
||||||
public:
|
|
||||||
using SPtr = std::shared_ptr<ExplainRoot>;
|
|
||||||
static SPtr createFromJson(Json::Value &json);
|
|
||||||
|
|
||||||
ExplainTreeModelItemPtr plan;
|
|
||||||
float planningTime = 0.f;
|
|
||||||
// Triggers???
|
|
||||||
float executionTime = 0.f;
|
|
||||||
float totalRuntime = 0.f;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "PgDatabaseCatalogue.h"
|
#include "PgDatabaseCatalogue.h"
|
||||||
#include "PgTypeContainer.h"
|
#include "PgTypeContainer.h"
|
||||||
#include "PgDatabaseContainer.h"
|
#include "PgDatabaseContainer.h"
|
||||||
#include "PgAuthIdContainer.h"
|
#include "PgAuthIdContainer.h"
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid)
|
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid)
|
||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
const PgAuthIdContainer *auth_ids = cat->authIds();
|
auto auth_ids = cat->authIds();
|
||||||
if (auth_ids) {
|
if (auth_ids) {
|
||||||
const PgAuthId& auth_id = auth_ids->getByOid(oid);
|
const PgAuthId& auth_id = auth_ids->getByOid(oid);
|
||||||
if (auth_id.valid()) {
|
if (auth_id.valid()) {
|
||||||
|
|
@ -18,6 +18,13 @@ QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString getRoleDisplayString(const PgDatabaseCatalogue *cat, Oid oid)
|
||||||
|
{
|
||||||
|
QString name = getRoleNameFromOid(cat, oid);
|
||||||
|
return QString("%1 (%2)").arg(name).arg(oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PgDatabaseCatalogue::PgDatabaseCatalogue()
|
PgDatabaseCatalogue::PgDatabaseCatalogue()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,5 +45,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid);
|
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid);
|
||||||
|
QString getRoleDisplayString(const PgDatabaseCatalogue *cat, Oid oid);
|
||||||
|
|
||||||
|
|
||||||
#endif // PGSQLDATABASECATALOGUE_H
|
#endif // PGSQLDATABASECATALOGUE_H
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "PgDatabaseContainer.h"
|
#include "PgDatabaseContainer.h"
|
||||||
#include "Pgsql_Connection.h"
|
#include "Pgsql_Connection.h"
|
||||||
|
#include "Pgsql_Col.h"
|
||||||
|
|
||||||
PgDatabaseContainer::PgDatabaseContainer(PgDatabaseCatalogue *cat)
|
PgDatabaseContainer::PgDatabaseContainer(PgDatabaseCatalogue *cat)
|
||||||
: PgContainer<PgDatabase>(cat)
|
: PgContainer<PgDatabase>(cat)
|
||||||
|
|
@ -17,18 +18,21 @@ void PgDatabaseContainer::load(const Pgsql::Result &res)
|
||||||
m_container.clear();
|
m_container.clear();
|
||||||
m_container.reserve(n_rows);
|
m_container.reserve(n_rows);
|
||||||
for (auto row : res) {
|
for (auto row : res) {
|
||||||
|
Pgsql::Col col(row);
|
||||||
PgDatabase v;
|
PgDatabase v;
|
||||||
v.oid << row.get(0); // InvalidOid;
|
// v.oid << row.get(0); // InvalidOid;
|
||||||
v.name << row.get(1);
|
// v.name << row.get(1);
|
||||||
v.dba << row.get(2); // owner?
|
// v.dba << row.get(2); // owner?
|
||||||
v.encoding << row.get(3);
|
// v.encoding << row.get(3);
|
||||||
v.collate << row.get(4);
|
// v.collate << row.get(4);
|
||||||
v.ctype << row.get(5);
|
// v.ctype << row.get(5);
|
||||||
v.isTemplate << row.get(6);
|
// v.isTemplate << row.get(6);
|
||||||
v.allowConn << row.get(7);
|
// v.allowConn << row.get(7);
|
||||||
v.connLimit << row.get(8);
|
// v.connLimit << row.get(8);
|
||||||
v.tablespace << row.get(9);
|
// v.tablespace << row.get(9);
|
||||||
v.acl << row.get(10);
|
// v.acl << row.get(10);
|
||||||
|
col >> v.oid >> v.name >> v.dba >> v.encoding >> v.collate >> v.ctype >> v.isTemplate
|
||||||
|
>> v.allowConn >> v.connLimit >> v.tablespace >> v.acl;
|
||||||
m_container.push_back(v);
|
m_container.push_back(v);
|
||||||
}
|
}
|
||||||
std::sort(m_container.begin(), m_container.end());
|
std::sort(m_container.begin(), m_container.end());
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ const int c_ColumnEstErr = 3;
|
||||||
const int c_ColumnRowCount = 4;
|
const int c_ColumnRowCount = 4;
|
||||||
const int c_ColumnLoops = 5;
|
const int c_ColumnLoops = 5;
|
||||||
const int c_ColumnDetails = 6;
|
const int c_ColumnDetails = 6;
|
||||||
const int c_NumberOfColumns = 7;
|
const int c_ColumnShared = 7;
|
||||||
|
const int c_NumberOfColumns = 8;
|
||||||
|
|
||||||
QueryExplainModel::QueryExplainModel(QObject *parent, ExplainRoot::SPtr exp)
|
QueryExplainModel::QueryExplainModel(QObject *parent, ExplainRoot::SPtr exp)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
|
|
@ -26,7 +27,7 @@ QVariant QueryExplainModel::data(const QModelIndex &index, int role) const
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
switch (col) {
|
switch (col) {
|
||||||
case c_ColumnNode:
|
case c_ColumnNode:
|
||||||
result = item->nodeType();
|
result = item->nodeType;
|
||||||
break;
|
break;
|
||||||
case c_ColumnExclusive:
|
case c_ColumnExclusive:
|
||||||
result = item->exclusiveTime();
|
result = item->exclusiveTime();
|
||||||
|
|
@ -38,14 +39,17 @@ if (role == Qt::DisplayRole) {
|
||||||
result = item->estimateError();
|
result = item->estimateError();
|
||||||
break;
|
break;
|
||||||
case c_ColumnRowCount:
|
case c_ColumnRowCount:
|
||||||
result = item->actualRows();
|
result = item->actualRows;
|
||||||
break;
|
break;
|
||||||
case c_ColumnLoops:
|
case c_ColumnLoops:
|
||||||
result = item->actualLoops();
|
result = item->actualLoops;
|
||||||
break;
|
break;
|
||||||
case c_ColumnDetails:
|
case c_ColumnDetails:
|
||||||
result = item->detailString();
|
result = item->detailString();
|
||||||
break;
|
break;
|
||||||
|
case c_ColumnShared:
|
||||||
|
result = item->sharedBlocks.asString();
|
||||||
|
break;
|
||||||
} // end switch column
|
} // end switch column
|
||||||
}
|
}
|
||||||
else if (role == Qt::TextAlignmentRole) {
|
else if (role == Qt::TextAlignmentRole) {
|
||||||
|
|
@ -133,6 +137,9 @@ QVariant QueryExplainModel::headerData(int section, Qt::Orientation orientation,
|
||||||
case c_ColumnDetails:
|
case c_ColumnDetails:
|
||||||
v = "Details";
|
v = "Details";
|
||||||
break;
|
break;
|
||||||
|
case c_ColumnShared:
|
||||||
|
v = "Shared";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else if (role == Qt::SizeHintRole) {
|
// else if (role == Qt::SizeHintRole) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "QueryResultModel.h"
|
#include "QueryResultModel.h"
|
||||||
|
#include "ResultTableModelUtil.h"
|
||||||
#include "Pgsql_declare.h"
|
#include "Pgsql_declare.h"
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
@ -36,7 +37,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
||||||
Oid o = result->type(col);
|
Oid o = result->type(col);
|
||||||
QString s(result->val(col, rij));
|
QString s(result->val(col, rij));
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case oid_bool:
|
case BOOLOID:
|
||||||
s = (s == "t") ? "TRUE" : "FALSE";
|
s = (s == "t") ? "TRUE" : "FALSE";
|
||||||
// intentional fall through
|
// intentional fall through
|
||||||
default:
|
default:
|
||||||
|
|
@ -50,23 +51,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (role == Qt::TextAlignmentRole) {
|
else if (role == Qt::TextAlignmentRole) {
|
||||||
Oid o = result->type(col);
|
r = GetDefaultAlignmentForType(result->type(col));
|
||||||
switch (o) {
|
|
||||||
case oid_int2:
|
|
||||||
case oid_int4:
|
|
||||||
case oid_int8:
|
|
||||||
case oid_float4:
|
|
||||||
case oid_float8:
|
|
||||||
case oid_numeric:
|
|
||||||
case oid_oid:
|
|
||||||
r = Qt::AlignRight + Qt::AlignVCenter;
|
|
||||||
break;
|
|
||||||
case oid_bool:
|
|
||||||
r = Qt::AlignCenter;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
r = Qt::AlignLeft + Qt::AlignVCenter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (role == Qt::ForegroundRole) {
|
else if (role == Qt::ForegroundRole) {
|
||||||
if (result->null(col, rij)) {
|
if (result->null(col, rij)) {
|
||||||
|
|
@ -75,19 +60,19 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
||||||
else {
|
else {
|
||||||
Oid o = result->type(col);
|
Oid o = result->type(col);
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case oid_int2:
|
case INT2OID:
|
||||||
case oid_int4:
|
case INT4OID:
|
||||||
case oid_int8:
|
case INT8OID:
|
||||||
r = QBrush(Qt::darkBlue);
|
r = QBrush(Qt::darkBlue);
|
||||||
break;
|
break;
|
||||||
case oid_float4:
|
case FLOAT4OID:
|
||||||
case oid_float8:
|
case FLOAT8OID:
|
||||||
r = QBrush(Qt::darkCyan);
|
r = QBrush(Qt::darkCyan);
|
||||||
break;
|
break;
|
||||||
case oid_numeric:
|
case NUMERICOID:
|
||||||
r = QBrush(Qt::darkGreen);
|
r = QBrush(Qt::darkGreen);
|
||||||
break;
|
break;
|
||||||
case oid_bool:
|
case BOOLOID:
|
||||||
if (strcmp(result->val(col, rij), "t") == 0) {
|
if (strcmp(result->val(col, rij), "t") == 0) {
|
||||||
r = QBrush(Qt::darkGreen);
|
r = QBrush(Qt::darkGreen);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "QueryTab.h"
|
#include "QueryTab.h"
|
||||||
#include "ui_QueryTab.h"
|
#include "ui_QueryTab.h"
|
||||||
#include "SqlSyntaxHighlighter.h"
|
#include "SqlSyntaxHighlighter.h"
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
@ -229,30 +229,32 @@ void QueryTab::explain(bool analyze)
|
||||||
|
|
||||||
std::string analyze_str;
|
std::string analyze_str;
|
||||||
if (analyze) {
|
if (analyze) {
|
||||||
analyze_str = "ANALYZE, ";
|
analyze_str = "ANALYZE, BUFFERS, ";
|
||||||
}
|
}
|
||||||
m_stopwatch.start();
|
m_stopwatch.start();
|
||||||
std::string cmd = "EXPLAIN (" + analyze_str + "VERBOSE, BUFFERS, FORMAT JSON) " + getCommandUtf8();
|
std::string cmd = "EXPLAIN (" + analyze_str + "VERBOSE, FORMAT JSON) " + getCommandUtf8();
|
||||||
m_dbConnection.send(cmd,
|
m_dbConnection.send(cmd,
|
||||||
[this](Expected<std::shared_ptr<Pgsql::Result>> exp_res, qint64 )
|
[this](Expected<std::shared_ptr<Pgsql::Result>> exp_res, qint64 )
|
||||||
{
|
{
|
||||||
if (exp_res.valid()) {
|
if (exp_res.valid()) {
|
||||||
// Process explain data seperately
|
// Process explain data seperately
|
||||||
auto res = exp_res.get();
|
auto res = exp_res.get();
|
||||||
std::thread([this,res]()
|
if (res) {
|
||||||
{
|
std::thread([this,res]()
|
||||||
std::shared_ptr<ExplainRoot> explain;
|
{
|
||||||
if (res->cols() == 1 && res->rows() == 1) {
|
std::shared_ptr<ExplainRoot> explain;
|
||||||
std::string s = res->val(0, 0);
|
if (res->cols() == 1 && res->rows() == 1) {
|
||||||
Json::Value root; // will contains the root value after parsing.
|
std::string s = res->val(0, 0);
|
||||||
Json::Reader reader;
|
Json::Value root; // will contains the root value after parsing.
|
||||||
bool parsingSuccessful = reader.parse(s, root);
|
Json::Reader reader;
|
||||||
if (parsingSuccessful) {
|
bool parsingSuccessful = reader.parse(s, root);
|
||||||
explain = ExplainRoot::createFromJson(root);
|
if (parsingSuccessful) {
|
||||||
|
explain = ExplainRoot::createFromJson(root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
m_win->QueueTask([this, explain]() { explain_ready(explain); });
|
||||||
m_win->QueueTask([this, explain]() { explain_ready(explain); });
|
}).detach();
|
||||||
}).detach();
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
57
pglab/ResultTableModelUtil.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include "ResultTableModelUtil.h"
|
||||||
|
|
||||||
|
using namespace Pgsql;
|
||||||
|
|
||||||
|
int GetDefaultAlignmentForType(Oid o)
|
||||||
|
{
|
||||||
|
|
||||||
|
int r;
|
||||||
|
switch (o) {
|
||||||
|
case INT2OID:
|
||||||
|
case INT4OID:
|
||||||
|
case INT8OID:
|
||||||
|
case FLOAT4OID:
|
||||||
|
case FLOAT8OID:
|
||||||
|
case NUMERICOID:
|
||||||
|
case OIDOID:
|
||||||
|
r = GetDefaultNumberAlignment();
|
||||||
|
break;
|
||||||
|
case BOOLOID:
|
||||||
|
r = GetDefaultBoolAlignment(); // Qt::AlignCenter;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r = GetDefaultAlignment();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor GetDefaultColorForType(Oid o)
|
||||||
|
{
|
||||||
|
QColor c;
|
||||||
|
switch (o) {
|
||||||
|
case INT2OID:
|
||||||
|
case INT4OID:
|
||||||
|
case INT8OID:
|
||||||
|
c = GetDefaultIntegerColor();
|
||||||
|
break;
|
||||||
|
case FLOAT4OID:
|
||||||
|
case FLOAT8OID:
|
||||||
|
c = GetDefaultFloatColor();
|
||||||
|
break;
|
||||||
|
case NUMERICOID:
|
||||||
|
c = GetDefaultNumericColor();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OIDOID:
|
||||||
|
case BOOLOID:
|
||||||
|
default:
|
||||||
|
c = Qt::black;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FormatBoolForDisplay(bool v)
|
||||||
|
{
|
||||||
|
return v ? "TRUE" : "FALSE";
|
||||||
|
}
|
||||||
|
|
||||||
23
pglab/ResultTableModelUtil.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Pgsql_declare.h"
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
int GetDefaultAlignmentForType(Oid oid);
|
||||||
|
QColor GetDefaultColorForType(Oid oid);
|
||||||
|
|
||||||
|
inline int GetDefaultAlignment() { return Qt::AlignLeft + Qt::AlignVCenter; }
|
||||||
|
inline int GetDefaultBoolAlignment() { return Qt::AlignCenter + Qt::AlignVCenter; }
|
||||||
|
inline int GetDefaultNumberAlignment() { return Qt::AlignRight + Qt::AlignVCenter; }
|
||||||
|
|
||||||
|
inline QColor GetDefaultBoolColor(bool v)
|
||||||
|
{
|
||||||
|
return v ? Qt::darkGreen : Qt::darkRed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QColor GetDefaultIntegerColor() { return Qt::darkBlue; }
|
||||||
|
inline QColor GetDefaultFloatColor() { return Qt::darkCyan; }
|
||||||
|
inline QColor GetDefaultNumericColor() { return Qt::darkGreen; }
|
||||||
|
|
||||||
|
QString FormatBoolForDisplay(bool v);
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "PgAuthIdContainer.h"
|
#include "PgAuthIdContainer.h"
|
||||||
|
|
||||||
RolesTableModel::RolesTableModel(QObject *parent)
|
RolesTableModel::RolesTableModel(QObject *parent)
|
||||||
: QAbstractTableModel(parent)
|
: BaseTableModel(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,50 +74,80 @@ int RolesTableModel::columnCount(const QModelIndex &parent) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant RolesTableModel::data(const QModelIndex &index, int role) const
|
Oid RolesTableModel::getType(int column) const
|
||||||
{
|
{
|
||||||
QVariant v;
|
using namespace Pgsql;
|
||||||
//if (!index.isValid())
|
|
||||||
if (m_roles) {
|
Oid oid;
|
||||||
const PgAuthId &authid = m_roles->getByIdx(index.row());
|
switch (column) {
|
||||||
if (role == Qt::DisplayRole) {
|
case NameCol:
|
||||||
switch (index.column()) {
|
oid = VARCHAROID;
|
||||||
case NameCol:
|
break;
|
||||||
v = authid.name;
|
|
||||||
break;
|
case ReplicationCol:
|
||||||
case SuperCol:
|
case BypassRlsCol:
|
||||||
// todo lookup role name
|
case CanLoginCol:
|
||||||
v = authid.super;
|
case CreateDBCol:
|
||||||
break;
|
case CreateRoleCol:
|
||||||
case InheritCol:
|
case InheritCol:
|
||||||
// todo lookup encoding name
|
case SuperCol:
|
||||||
v = authid.inherit;
|
oid = BOOLOID;
|
||||||
break;
|
break;
|
||||||
case CreateRoleCol:
|
|
||||||
v = authid.createRole;
|
case ConnlimitCol:
|
||||||
break;
|
oid = INT4OID;
|
||||||
case CreateDBCol:
|
break;
|
||||||
v = authid.createDB;
|
|
||||||
break;
|
case ValidUntilCol:
|
||||||
case CanLoginCol:
|
oid = TIMESTAMPOID;
|
||||||
v = authid.canlogin;
|
break;
|
||||||
break;
|
default:
|
||||||
case ReplicationCol:
|
oid = InvalidOid;
|
||||||
v = authid.replication;
|
|
||||||
break;
|
|
||||||
case BypassRlsCol:
|
|
||||||
v = authid.bypassRls;
|
|
||||||
break;
|
|
||||||
case ConnlimitCol:
|
|
||||||
// todo lookup tablespace name
|
|
||||||
v = authid.connLimit;
|
|
||||||
break;
|
|
||||||
case ValidUntilCol:
|
|
||||||
v = authid.validUntil;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant RolesTableModel::getData(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
if (m_roles) {
|
||||||
|
const PgAuthId &authid = m_roles->getByIdx(index.row());
|
||||||
|
switch (index.column()) {
|
||||||
|
case NameCol:
|
||||||
|
v = authid.name;
|
||||||
|
break;
|
||||||
|
case SuperCol:
|
||||||
|
// todo lookup role name
|
||||||
|
v = authid.super;
|
||||||
|
break;
|
||||||
|
case InheritCol:
|
||||||
|
// todo lookup encoding name
|
||||||
|
v = authid.inherit;
|
||||||
|
break;
|
||||||
|
case CreateRoleCol:
|
||||||
|
v = authid.createRole;
|
||||||
|
break;
|
||||||
|
case CreateDBCol:
|
||||||
|
v = authid.createDB;
|
||||||
|
break;
|
||||||
|
case CanLoginCol:
|
||||||
|
v = authid.canlogin;
|
||||||
|
break;
|
||||||
|
case ReplicationCol:
|
||||||
|
v = authid.replication;
|
||||||
|
break;
|
||||||
|
case BypassRlsCol:
|
||||||
|
v = authid.bypassRls;
|
||||||
|
break;
|
||||||
|
case ConnlimitCol:
|
||||||
|
// todo lookup tablespace name
|
||||||
|
v = authid.connLimit;
|
||||||
|
break;
|
||||||
|
case ValidUntilCol:
|
||||||
|
v = authid.validUntil;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
#define ROLESTABLEMODEL_H
|
#define ROLESTABLEMODEL_H
|
||||||
|
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include "BaseTableModel.h"
|
||||||
|
|
||||||
class PgAuthIdContainer;
|
class PgAuthIdContainer;
|
||||||
|
|
||||||
/** Class for displaying the list of roles of a server in a QTableView
|
/** Class for displaying the list of roles of a server in a QTableView
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class RolesTableModel : public QAbstractTableModel {
|
class RolesTableModel : public BaseTableModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum e_Columns : int { NameCol, SuperCol, InheritCol, CreateRoleCol,
|
enum e_Columns : int { NameCol, SuperCol, InheritCol, CreateRoleCol,
|
||||||
|
|
@ -29,7 +29,10 @@ public:
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual Oid getType(int column) const override;
|
||||||
|
virtual QVariant getData(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
// QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PgAuthIdContainer *m_roles = nullptr;
|
const PgAuthIdContainer *m_roles = nullptr;
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 416 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 471 B After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 473 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 419 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 525 B After Width: | Height: | Size: 1.3 KiB |
|
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
|
|
||||||
CONFIG += c++14
|
CONFIG += c++17
|
||||||
QT += core gui
|
QT += core gui
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
||||||
|
|
@ -13,7 +13,7 @@ TARGET = pglab
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
INCLUDEPATH += C:\prog\include C:\Prog\include\pgsql C:\VSproj\boost32\include\boost-1_65_1
|
INCLUDEPATH += C:\prog\include C:\Prog\include\pgsql C:\VSproj\boost32\include\boost-1_65_1
|
||||||
DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX
|
DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX _WIN32_WINNT=0x0501
|
||||||
#LIBS += -LC:/prog/boost/lib -Lc:/prog/lib libpq.lib fmt.lib User32.lib ws2_32.lib
|
#LIBS += -LC:/prog/boost/lib -Lc:/prog/lib libpq.lib fmt.lib User32.lib ws2_32.lib
|
||||||
LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
|
LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
|
||||||
|
|
||||||
|
|
@ -29,9 +29,7 @@ win32:RC_ICONS += pglab.ico
|
||||||
|
|
||||||
SOURCES += main.cpp\
|
SOURCES += main.cpp\
|
||||||
QueryResultModel.cpp \
|
QueryResultModel.cpp \
|
||||||
jsoncpp.cpp \
|
|
||||||
QueryExplainModel.cpp \
|
QueryExplainModel.cpp \
|
||||||
ExplainTreeModelItem.cpp \
|
|
||||||
ASyncDBConnection.cpp \
|
ASyncDBConnection.cpp \
|
||||||
tsqueue.cpp \
|
tsqueue.cpp \
|
||||||
DatabaseWindow.cpp \
|
DatabaseWindow.cpp \
|
||||||
|
|
@ -68,12 +66,13 @@ PgDatabaseCatalogue.cpp \
|
||||||
ConnectionList.cpp \
|
ConnectionList.cpp \
|
||||||
ProcessStdioWidget.cpp \
|
ProcessStdioWidget.cpp \
|
||||||
GlobalIoService.cpp \
|
GlobalIoService.cpp \
|
||||||
CodeBuilderConfiguration.cpp
|
CodeBuilderConfiguration.cpp \
|
||||||
|
ResultTableModelUtil.cpp \
|
||||||
|
BaseTableModel.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
QueryResultModel.h \
|
QueryResultModel.h \
|
||||||
QueryExplainModel.h \
|
QueryExplainModel.h \
|
||||||
ExplainTreeModelItem.h \
|
|
||||||
ASyncDBConnection.h \
|
ASyncDBConnection.h \
|
||||||
tsqueue.h \
|
tsqueue.h \
|
||||||
DatabaseWindow.h \
|
DatabaseWindow.h \
|
||||||
|
|
@ -110,7 +109,9 @@ PgDatabaseCatalogue.h \
|
||||||
ConnectionList.h \
|
ConnectionList.h \
|
||||||
ProcessStdioWidget.h \
|
ProcessStdioWidget.h \
|
||||||
GlobalIoService.h \
|
GlobalIoService.h \
|
||||||
CodeBuilderConfiguration.h
|
CodeBuilderConfiguration.h \
|
||||||
|
ResultTableModelUtil.h \
|
||||||
|
BaseTableModel.h
|
||||||
|
|
||||||
FORMS += mainwindow.ui \
|
FORMS += mainwindow.ui \
|
||||||
DatabaseWindow.ui \
|
DatabaseWindow.ui \
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>icons/server_delete.png</file>
|
<file>icons/server_delete.png</file>
|
||||||
<file>icons/server_go.png</file>
|
|
||||||
<file>icons/script_delete.png</file>
|
<file>icons/script_delete.png</file>
|
||||||
<file>icons/script_go.png</file>
|
<file>icons/script_go.png</file>
|
||||||
<file>icons/folder.png</file>
|
<file>icons/folder.png</file>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ TEMPLATE = subdirs
|
||||||
|
|
||||||
DEFINES += BOOST_ENABLE_ASSERT_HANDLER
|
DEFINES += BOOST_ENABLE_ASSERT_HANDLER
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS += core \
|
SUBDIRS += core \
|
||||||
pgsql \
|
pgsql \
|
||||||
pglab
|
pglab
|
||||||
|
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
# SUBDIRS += tests
|
SUBDIRS += tests
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
pgsql/Pgsql_Col.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include "Pgsql_Col.h"
|
||||||
|
|
||||||
39
pgsql/Pgsql_Col.h
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef PGSQL_COL_H
|
||||||
|
#define PGSQL_COL_H
|
||||||
|
|
||||||
|
#include "Pgsql_Row.h"
|
||||||
|
|
||||||
|
namespace Pgsql {
|
||||||
|
|
||||||
|
class Col {
|
||||||
|
public:
|
||||||
|
explicit Col(Pgsql::Row &r)
|
||||||
|
: row(r)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void reset() { col = -1; }
|
||||||
|
Pgsql::Value nextValue()
|
||||||
|
{
|
||||||
|
return row.get(++col);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Pgsql::Row &row;
|
||||||
|
int col = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// template <typename T>
|
||||||
|
// void operator<<(T &s, Col &c)
|
||||||
|
// {
|
||||||
|
// s << c.nextValue();
|
||||||
|
// }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Col& operator>>(Col &c, T &s)
|
||||||
|
{
|
||||||
|
s << c.nextValue();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace Pgsql
|
||||||
|
|
||||||
|
#endif // PGSQL_COL_H
|
||||||
|
|
@ -22,8 +22,8 @@ namespace Pgsql {
|
||||||
*
|
*
|
||||||
* The class takes ownership of data and will try to delete[] it.
|
* The class takes ownership of data and will try to delete[] it.
|
||||||
*/
|
*/
|
||||||
void addText(const char *data, Oid oid=oid_varchar);
|
void addText(const char *data, Oid oid=VARCHAROID);
|
||||||
void add(const QString &s, Oid oid=oid_varchar);
|
void add(const QString &s, Oid oid=VARCHAROID);
|
||||||
void addBinary(const char *data, int length, Oid oid);
|
void addBinary(const char *data, int length, Oid oid);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ namespace Pgsql {
|
||||||
Value get(int col) const;
|
Value get(int col) const;
|
||||||
//Value get(const char *colname) const;
|
//Value get(const char *colname) const;
|
||||||
//bool get(int col, QString &s);
|
//bool get(int col, QString &s);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Result& m_result;
|
const Result& m_result;
|
||||||
int m_row;
|
int m_row;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
using namespace Pgsql;
|
using namespace Pgsql;
|
||||||
|
|
||||||
Value::Value(const char *val, Oid typ)
|
Value::Value(const char *val, Oid typ)
|
||||||
: m_val(val), m_typ(typ)
|
: m_val(val)
|
||||||
|
, m_typ(typ)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QString Value::asQString() const
|
QString Value::asQString() const
|
||||||
|
|
@ -15,15 +16,30 @@ QString Value::asQString() const
|
||||||
|
|
||||||
Value::operator QString() const
|
Value::operator QString() const
|
||||||
{
|
{
|
||||||
return QString::fromUtf8(m_val);
|
// if (isString())
|
||||||
|
return QString::fromUtf8(m_val);
|
||||||
|
// else
|
||||||
|
// throw std::logic_error("Column type doesn't match requested type");
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::operator QDateTime() const
|
Value::operator QDateTime() const
|
||||||
{
|
{
|
||||||
return QDateTime::fromString(asQString(),
|
return QDateTime::fromString(asQString(), Qt::ISODateWithMs);
|
||||||
"yyyy-MM-dd hh:mm:ss");
|
// return QDateTime::fromString(asQString(),
|
||||||
|
// "yyyy-MM-dd hh:mm:ss");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::operator QDate() const
|
||||||
|
{
|
||||||
|
return QDate::fromString(asQString(), Qt::ISODate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::operator QTime() const
|
||||||
|
{
|
||||||
|
return QTime::fromString(asQString(), Qt::ISODateWithMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Value::operator std::string() const
|
Value::operator std::string() const
|
||||||
{
|
{
|
||||||
return m_val;
|
return m_val;
|
||||||
|
|
@ -54,6 +70,14 @@ Value::operator bool() const
|
||||||
return std::strcmp(m_val, "t") == 0;
|
return std::strcmp(m_val, "t") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Value::isString() const
|
||||||
|
{
|
||||||
|
return m_typ == CHAROID
|
||||||
|
|| m_typ == VARCHAROID
|
||||||
|
|| m_typ == TEXTOID
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//void operator<<(QString &s, const Value &v)
|
//void operator<<(QString &s, const Value &v)
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,17 @@ namespace Pgsql {
|
||||||
|
|
||||||
operator QString() const;
|
operator QString() const;
|
||||||
operator QDateTime() const;
|
operator QDateTime() const;
|
||||||
|
operator QDate() const;
|
||||||
|
operator QTime() const;
|
||||||
operator std::string() const;
|
operator std::string() const;
|
||||||
operator short() const;
|
operator short() const;
|
||||||
operator int() const;
|
operator int() const;
|
||||||
operator Oid() const;
|
operator Oid() const;
|
||||||
operator long long() const;
|
operator long long() const;
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
|
||||||
|
bool isString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *m_val;
|
const char *m_val;
|
||||||
Oid m_typ;
|
Oid m_typ;
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,95 @@
|
||||||
|
|
||||||
namespace Pgsql {
|
namespace Pgsql {
|
||||||
|
|
||||||
const Oid oid_bool = 16;
|
const Oid BOOLOID = 16;
|
||||||
const Oid oid_int2 = 21;
|
const Oid BYTEAOID = 17;
|
||||||
const Oid oid_int4 = 23;
|
const Oid CHAROID = 18;
|
||||||
const Oid oid_int8 = 20;
|
const Oid NAMEOID = 19;
|
||||||
const Oid oid_float4 = 700;
|
const Oid INT8OID = 20;
|
||||||
const Oid oid_float8 = 701;
|
const Oid INT2OID = 21;
|
||||||
const Oid oid_numeric = 1700;
|
const Oid INT2VECTOROID = 22;
|
||||||
const Oid oid_oid = 26;
|
const Oid INT4OID = 23;
|
||||||
const Oid oid_varchar = 1043;
|
const Oid REGPROCOID = 24;
|
||||||
|
const Oid TEXTOID = 25;
|
||||||
|
const Oid OIDOID = 26;
|
||||||
|
const Oid TIDOID = 27;
|
||||||
|
const Oid XIDOID = 28;
|
||||||
|
const Oid CIDOID = 29;
|
||||||
|
const Oid OIDVECTOROID = 30;
|
||||||
|
const Oid JSONOID = 114;
|
||||||
|
const Oid XMLOID = 142;
|
||||||
|
const Oid PGNODETREEOID = 194;
|
||||||
|
const Oid PGDDLCOMMANDOID = 32;
|
||||||
|
const Oid POINTOID = 600;
|
||||||
|
const Oid LSEGOID = 601;
|
||||||
|
const Oid PATHOID = 602;
|
||||||
|
const Oid BOXOID = 603;
|
||||||
|
const Oid POLYGONOID = 604;
|
||||||
|
const Oid LINEOID = 628;
|
||||||
|
const Oid FLOAT4OID = 700;
|
||||||
|
const Oid FLOAT8OID = 701;
|
||||||
|
const Oid ABSTIMEOID = 702;
|
||||||
|
const Oid RELTIMEOID = 703;
|
||||||
|
const Oid TINTERVALOID = 704;
|
||||||
|
const Oid UNKNOWNOID = 705;
|
||||||
|
const Oid CIRCLEOID = 718;
|
||||||
|
const Oid CASHOID = 790;
|
||||||
|
const Oid MACADDROID = 829;
|
||||||
|
const Oid INETOID = 869;
|
||||||
|
const Oid CIDROID = 650;
|
||||||
|
const Oid INT2ARRAYOID = 1005;
|
||||||
|
const Oid INT4ARRAYOID = 1007;
|
||||||
|
const Oid TEXTARRAYOID = 1009;
|
||||||
|
const Oid OIDARRAYOID = 1028;
|
||||||
|
const Oid FLOAT4ARRAYOID = 1021;
|
||||||
|
const Oid ACLITEMOID = 1033;
|
||||||
|
const Oid CSTRINGARRAYOID = 1263;
|
||||||
|
const Oid BPCHAROID = 1042;
|
||||||
|
const Oid VARCHAROID = 1043;
|
||||||
|
const Oid DATEOID = 1082;
|
||||||
|
const Oid TIMEOID = 1083;
|
||||||
|
const Oid TIMESTAMPOID = 1114;
|
||||||
|
const Oid TIMESTAMPTZOID = 1184;
|
||||||
|
const Oid INTERVALOID = 1186;
|
||||||
|
const Oid TIMETZOID = 1266;
|
||||||
|
const Oid BITOID = 1560;
|
||||||
|
const Oid VARBITOID = 1562;
|
||||||
|
const Oid NUMERICOID = 1700;
|
||||||
|
const Oid REFCURSOROID = 1790;
|
||||||
|
const Oid REGPROCEDUREOID = 2202;
|
||||||
|
const Oid REGOPEROID = 2203;
|
||||||
|
const Oid REGOPERATOROID = 2204;
|
||||||
|
const Oid REGCLASSOID = 2205;
|
||||||
|
const Oid REGTYPEOID = 2206;
|
||||||
|
const Oid REGROLEOID = 4096;
|
||||||
|
const Oid REGNAMESPACEOID = 4089;
|
||||||
|
const Oid REGTYPEARRAYOID = 2211;
|
||||||
|
const Oid UUIDOID = 2950;
|
||||||
|
const Oid LSNOID = 3220;
|
||||||
|
const Oid TSVECTOROID = 3614;
|
||||||
|
const Oid GTSVECTOROID = 3642;
|
||||||
|
const Oid TSQUERYOID = 3615;
|
||||||
|
const Oid REGCONFIGOID = 3734;
|
||||||
|
const Oid REGDICTIONARYOID = 3769;
|
||||||
|
const Oid JSONBOID = 3802;
|
||||||
|
const Oid INT4RANGEOID = 3904;
|
||||||
|
const Oid RECORDOID = 2249;
|
||||||
|
const Oid RECORDARRAYOID = 2287;
|
||||||
|
const Oid CSTRINGOID = 2275;
|
||||||
|
const Oid ANYOID = 2276;
|
||||||
|
const Oid ANYARRAYOID = 2277;
|
||||||
|
const Oid VOIDOID = 2278;
|
||||||
|
const Oid TRIGGEROID = 2279;
|
||||||
|
const Oid EVTTRIGGEROID = 3838;
|
||||||
|
const Oid LANGUAGE_HANDLEROID = 2280;
|
||||||
|
const Oid INTERNALOID = 2281;
|
||||||
|
const Oid OPAQUEOID = 2282;
|
||||||
|
const Oid ANYELEMENTOID = 2283;
|
||||||
|
const Oid ANYNONARRAYOID = 2776;
|
||||||
|
const Oid ANYENUMOID = 3500;
|
||||||
|
const Oid FDW_HANDLEROID = 3115;
|
||||||
|
const Oid TSM_HANDLEROID = 3310;
|
||||||
|
const Oid ANYRANGEOID = 3831;
|
||||||
|
|
||||||
|
|
||||||
class Params;
|
class Params;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
||||||
TARGET = pgsql
|
TARGET = pgsql
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
INCLUDEPATH += C:\prog\include C:\Prog\include\pgsql C:\VSproj\boost32\include\boost-1_65_1
|
INCLUDEPATH += C:\prog\include \
|
||||||
|
C:\Prog\include\pgsql \
|
||||||
|
C:\VSproj\boost32\include\boost-1_65_1
|
||||||
|
|
||||||
DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX
|
DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX
|
||||||
#LIBS += -LC:/prog/boost/lib -Lc:/prog/lib libpq.lib fmt.lib User32.lib ws2_32.lib
|
#LIBS += -LC:/prog/boost/lib -Lc:/prog/lib libpq.lib fmt.lib User32.lib ws2_32.lib
|
||||||
LIBS += -LC:/PROG/LIB -lws2_32 -llibpq
|
LIBS += -LC:/PROG/LIB -lws2_32 -llibpq
|
||||||
|
|
@ -31,14 +34,16 @@ SOURCES += Pgsql_Connection.cpp \
|
||||||
Pgsql_Params.cpp \
|
Pgsql_Params.cpp \
|
||||||
Pgsql_Result.cpp \
|
Pgsql_Result.cpp \
|
||||||
Pgsql_Row.cpp \
|
Pgsql_Row.cpp \
|
||||||
Pgsql_Value.cpp
|
Pgsql_Value.cpp \
|
||||||
|
Pgsql_Col.cpp
|
||||||
|
|
||||||
HEADERS += Pgsql_Connection.h \
|
HEADERS += Pgsql_Connection.h \
|
||||||
Pgsql_Params.h \
|
Pgsql_Params.h \
|
||||||
Pgsql_Result.h \
|
Pgsql_Result.h \
|
||||||
Pgsql_Row.h \
|
Pgsql_Row.h \
|
||||||
Pgsql_Value.h \
|
Pgsql_Value.h \
|
||||||
Pgsql_declare.h
|
Pgsql_declare.h \
|
||||||
|
Pgsql_Col.h
|
||||||
|
|
||||||
#FORMS +=
|
#FORMS +=
|
||||||
|
|
||||||
|
|
|
||||||
73
tests/PgsqlTests/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# This file is used to ignore files which are generated
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.autosave
|
||||||
|
*.a
|
||||||
|
*.core
|
||||||
|
*.moc
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*_pch.h.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*.qm
|
||||||
|
.#*
|
||||||
|
*.*#
|
||||||
|
core
|
||||||
|
!core/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
*.debug
|
||||||
|
Makefile*
|
||||||
|
*.prl
|
||||||
|
*.app
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
Thumbs.db
|
||||||
|
*.res
|
||||||
|
*.rc
|
||||||
|
/.qmake.cache
|
||||||
|
/.qmake.stash
|
||||||
|
|
||||||
|
# qtcreator generated files
|
||||||
|
*.pro.user*
|
||||||
|
|
||||||
|
# xemacs temporary files
|
||||||
|
*.flc
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# Visual Studio generated files
|
||||||
|
*.ib_pdb_index
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.vcproj
|
||||||
|
*vcproj.*.*.user
|
||||||
|
*.ncb
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*vcxproj.*
|
||||||
|
|
||||||
|
# MinGW generated files
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# Python byte code
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
# --------
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
||||||
43
tests/PgsqlTests/PgsqlTests.pro
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
include(gtest_dependency.pri)
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console c++11
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG += thread
|
||||||
|
CONFIG += qt
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
INCLUDEPATH += C:\prog\include C:\Prog\include\pgsql
|
||||||
|
|
||||||
|
HEADERS +=
|
||||||
|
|
||||||
|
SOURCES += main.cpp \
|
||||||
|
tst_Value.cpp
|
||||||
|
|
||||||
|
|
||||||
|
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../pgsql/release/ -lpgsql
|
||||||
|
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../pgsql/debug/ -lpgsql
|
||||||
|
else:unix: LIBS += -L$$OUT_PWD/../../pgsql/ -lpgsql
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD/../../pgsql
|
||||||
|
DEPENDPATH += $$PWD/../../pgsql
|
||||||
|
|
||||||
|
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/release/libpgsql.a
|
||||||
|
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/debug/libpgsql.a
|
||||||
|
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/release/pgsql.lib
|
||||||
|
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/debug/pgsql.lib
|
||||||
|
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/libpgsql.a
|
||||||
|
|
||||||
|
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/release/ -lmygtestutils
|
||||||
|
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/debug/ -lmygtestutils
|
||||||
|
else:unix:!macx: LIBS += -L$$OUT_PWD/../mygtestutils/ -lmygtestutils
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD/../mygtestutils
|
||||||
|
DEPENDPATH += $$PWD/../mygtestutils
|
||||||
|
|
||||||
|
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/libmygtestutils.a
|
||||||
|
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/libmygtestutils.a
|
||||||
|
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/mygtestutils.lib
|
||||||
|
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/mygtestutils.lib
|
||||||
|
else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/libmygtestutils.a
|
||||||
29
tests/PgsqlTests/gtest_dependency.pri
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
isEmpty(GOOGLETEST_DIR):GOOGLETEST_DIR=$$(GOOGLETEST_DIR)
|
||||||
|
|
||||||
|
isEmpty(GOOGLETEST_DIR) {
|
||||||
|
warning("Using googletest src dir specified at Qt Creator wizard")
|
||||||
|
message("set GOOGLETEST_DIR as environment variable or qmake variable to get rid of this message")
|
||||||
|
GOOGLETEST_DIR = C:/Prog/googletest
|
||||||
|
}
|
||||||
|
|
||||||
|
!isEmpty(GOOGLETEST_DIR): {
|
||||||
|
GTEST_SRCDIR = $$GOOGLETEST_DIR/googletest
|
||||||
|
GMOCK_SRCDIR = $$GOOGLETEST_DIR/googlemock
|
||||||
|
}
|
||||||
|
|
||||||
|
requires(exists($$GTEST_SRCDIR):exists($$GMOCK_SRCDIR))
|
||||||
|
|
||||||
|
!exists($$GOOGLETEST_DIR):message("No googletest src dir found - set GOOGLETEST_DIR to enable.")
|
||||||
|
|
||||||
|
DEFINES += \
|
||||||
|
GTEST_LANG_CXX11
|
||||||
|
|
||||||
|
INCLUDEPATH *= \
|
||||||
|
$$GTEST_SRCDIR \
|
||||||
|
$$GTEST_SRCDIR/include \
|
||||||
|
$$GMOCK_SRCDIR \
|
||||||
|
$$GMOCK_SRCDIR/include
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$GTEST_SRCDIR/src/gtest-all.cc \
|
||||||
|
$$GMOCK_SRCDIR/src/gmock-all.cc
|
||||||
7
tests/PgsqlTests/main.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
66
tests/PgsqlTests/tst_Value.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "Pgsql_Value.h"
|
||||||
|
#include "PrintTo_Qt.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
using namespace Pgsql;
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, test_int4)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("1", INT4OID);
|
||||||
|
int i = (int)v;
|
||||||
|
ASSERT_EQ(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, test_QDateTime)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("2017-10-22 12:34:56", TIMESTAMPTZOID);
|
||||||
|
QDateTime dt = (QDateTime)v;
|
||||||
|
ASSERT_EQ(dt, QDateTime(QDate(2017, 10, 22), QTime(12, 34, 56)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, test_QDateTime_2)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("2017-12-01 09:38:17.339817+02", TIMESTAMPTZOID);
|
||||||
|
QDateTime dt = (QDateTime)v;
|
||||||
|
QDateTime exp(QDate(2017, 12, 1), QTime(9, 38, 17, 340),
|
||||||
|
Qt::OffsetFromUTC, 2*3600);
|
||||||
|
ASSERT_EQ(dt, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, test_QDate)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("2017-10-22", DATEOID);
|
||||||
|
QDate d = v;
|
||||||
|
ASSERT_EQ(d, QDate(2017, 10, 22));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, test_QTime)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("12:34:56", TIMEOID);
|
||||||
|
QTime t = v;
|
||||||
|
ASSERT_EQ(t, QTime(12, 34, 56));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, test_QTimeMS)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("09:38:17.339817+02", TIMETZOID);
|
||||||
|
QTime t = v;
|
||||||
|
ASSERT_EQ(t, QTime(9, 38, 17, 340));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, isString_int4)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("1", INT4OID);
|
||||||
|
ASSERT_EQ(v.isString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pgsql_Value, isString_varchar)
|
||||||
|
{
|
||||||
|
Pgsql::Value v("1", VARCHAROID);
|
||||||
|
ASSERT_EQ(v.isString(), true);
|
||||||
|
}
|
||||||
3
tests/auto/auto.pro
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
SUBDIRS += mycase
|
||||||
29
tests/auto/gtest_dependency.pri
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
isEmpty(GOOGLETEST_DIR):GOOGLETEST_DIR=$$(GOOGLETEST_DIR)
|
||||||
|
|
||||||
|
isEmpty(GOOGLETEST_DIR) {
|
||||||
|
warning("Using googletest src dir specified at Qt Creator wizard")
|
||||||
|
message("set GOOGLETEST_DIR as environment variable or qmake variable to get rid of this message")
|
||||||
|
GOOGLETEST_DIR = C:/Prog/googletest
|
||||||
|
}
|
||||||
|
|
||||||
|
!isEmpty(GOOGLETEST_DIR): {
|
||||||
|
GTEST_SRCDIR = $$GOOGLETEST_DIR/googletest
|
||||||
|
GMOCK_SRCDIR = $$GOOGLETEST_DIR/googlemock
|
||||||
|
}
|
||||||
|
|
||||||
|
requires(exists($$GTEST_SRCDIR):exists($$GMOCK_SRCDIR))
|
||||||
|
|
||||||
|
!exists($$GOOGLETEST_DIR):message("No googletest src dir found - set GOOGLETEST_DIR to enable.")
|
||||||
|
|
||||||
|
DEFINES += \
|
||||||
|
GTEST_LANG_CXX11
|
||||||
|
|
||||||
|
INCLUDEPATH *= \
|
||||||
|
$$GTEST_SRCDIR \
|
||||||
|
$$GTEST_SRCDIR/include \
|
||||||
|
$$GMOCK_SRCDIR \
|
||||||
|
$$GMOCK_SRCDIR/include
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$GTEST_SRCDIR/src/gtest-all.cc \
|
||||||
|
$$GMOCK_SRCDIR/src/gmock-all.cc
|
||||||
13
tests/auto/mycase/main.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "tst_CsvWriter.h"
|
||||||
|
#include "tst_expected.h"
|
||||||
|
#include "tst_PasswordManager.h"
|
||||||
|
#include "tst_scopeguard.h"
|
||||||
|
#include "tst_SqlLexer.h"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
32
tests/auto/mycase/mycase.pro
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
include(../gtest_dependency.pri)
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console c++11
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG += thread
|
||||||
|
CONFIG += qt
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
tst_expected.h \
|
||||||
|
tst_SqlLexer.h \
|
||||||
|
tst_scopeguard.h \
|
||||||
|
tst_CsvWriter.h \
|
||||||
|
tst_PasswordManager.h
|
||||||
|
|
||||||
|
SOURCES += main.cpp \
|
||||||
|
tst_ExplainJsonParser.cpp
|
||||||
|
|
||||||
|
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../core/release/ -lcore
|
||||||
|
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../core/debug/ -lcore
|
||||||
|
|
||||||
|
INCLUDEPATH += C:\prog\include C:\VSproj\boost_1_63_0
|
||||||
|
INCLUDEPATH += $$PWD/../../../core
|
||||||
|
DEPENDPATH += $$PWD/../../../core
|
||||||
|
LIBS += c:\prog\lib\botand_imp.lib
|
||||||
|
|
||||||
|
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/release/libcore.a
|
||||||
|
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/debug/libcore.a
|
||||||
|
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/release/core.lib
|
||||||
|
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/debug/core.lib
|
||||||
113
tests/auto/mycase/tst_CsvWriter.h
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "CsvWriter.h"
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
|
||||||
|
TEST(CsvWriter, one_row_two_numbers)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('"');
|
||||||
|
writer.setSeperator(',');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("2");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1,2\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CsvWriter, one_row_one_number_one_unquoted_string)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('"');
|
||||||
|
writer.setSeperator(',');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("hello");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1,hello\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CsvWriter, one_row_one_number_one_quoted_string)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('"');
|
||||||
|
writer.setSeperator(',');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("hel,lo");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1,\"hel,lo\"\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CsvWriter, newline_in_field)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('"');
|
||||||
|
writer.setSeperator(',');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("hel\nlo");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1,\"hel\nlo\"\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CsvWriter, escape_quote)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('"');
|
||||||
|
writer.setSeperator(',');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("hel\"lo");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1,\"hel\"\"lo\"\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CsvWriter, non_default_seperator)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('"');
|
||||||
|
writer.setSeperator('\t');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("hel,lo");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1\thel,lo\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CsvWriter, non_default_quote)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
QTextStream stream(&result);
|
||||||
|
CsvWriter writer(&stream);
|
||||||
|
writer.setQuote('*');
|
||||||
|
writer.setSeperator('\t');
|
||||||
|
writer.writeField("1");
|
||||||
|
writer.writeField("hel\tlo");
|
||||||
|
writer.nextRow();
|
||||||
|
|
||||||
|
QString expected = QString::fromUtf8("1\t*hel\tlo*\n");
|
||||||
|
ASSERT_THAT(result, Eq(expected));
|
||||||
|
}
|
||||||
80
tests/auto/mycase/tst_ExplainJsonParser.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "ExplainTreeModelItem.h"
|
||||||
|
#include "json/json.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ExplainParser, verbose)
|
||||||
|
{
|
||||||
|
std::string input = R"__json__("[
|
||||||
|
{
|
||||||
|
"Plan": {
|
||||||
|
"Node Type": "Limit",
|
||||||
|
"Parallel Aware": false,
|
||||||
|
"Startup Cost": 0.42,
|
||||||
|
"Total Cost": 0.42,
|
||||||
|
"Plan Rows": 10,
|
||||||
|
"Plan Width": 830,
|
||||||
|
"Output": ["fr1.callstack_crc_2", "fr1.id", "fr1.program", "fr1.version", "fr1.lic_bedrijf", "fr1.lic_plaats", "fr1.lic_number", "fr1.callstack_crc_1", "fr1.callstack_crc_3", "fr1.exception_class", "fr1.exception_message", "fr1.full_report", "fr1.screenshot_filename", "fr1.ts", "fr1.duplicate_of", "fr1.actief", "fr1.commentaar", "fr1.bugzilla", "fr1.attachment_filename", "fr1.version_according_to_datetime", "fr1.program_according_to_full_report", "fr1.date", "fr2.id", "fr2.program", "fr2.version", "fr2.lic_bedrijf", "fr2.lic_plaats", "fr2.lic_number", "fr2.callstack_crc_1", "fr2.callstack_crc_3", "fr2.exception_class", "fr2.exception_message", "fr2.full_report", "fr2.screenshot_filename", "fr2.ts", "fr2.duplicate_of", "fr2.actief", "fr2.commentaar", "fr2.bugzilla", "fr2.attachment_filename", "fr2.version_according_to_datetime", "fr2.program_according_to_full_report", "fr2.date"],
|
||||||
|
"Plans": [
|
||||||
|
{
|
||||||
|
"Node Type": "Nested Loop",
|
||||||
|
"Parent Relationship": "Outer",
|
||||||
|
"Parallel Aware": false,
|
||||||
|
"Join Type": "Inner",
|
||||||
|
"Startup Cost": 0.42,
|
||||||
|
"Total Cost": 103148.97,
|
||||||
|
"Plan Rows": 493512899,
|
||||||
|
"Plan Width": 830,
|
||||||
|
"Output": ["fr1.callstack_crc_2", "fr1.id", "fr1.program", "fr1.version", "fr1.lic_bedrijf", "fr1.lic_plaats", "fr1.lic_number", "fr1.callstack_crc_1", "fr1.callstack_crc_3", "fr1.exception_class", "fr1.exception_message", "fr1.full_report", "fr1.screenshot_filename", "fr1.ts", "fr1.duplicate_of", "fr1.actief", "fr1.commentaar", "fr1.bugzilla", "fr1.attachment_filename", "fr1.version_according_to_datetime", "fr1.program_according_to_full_report", "fr1.date", "fr2.id", "fr2.program", "fr2.version", "fr2.lic_bedrijf", "fr2.lic_plaats", "fr2.lic_number", "fr2.callstack_crc_1", "fr2.callstack_crc_3", "fr2.exception_class", "fr2.exception_message", "fr2.full_report", "fr2.screenshot_filename", "fr2.ts", "fr2.duplicate_of", "fr2.actief", "fr2.commentaar", "fr2.bugzilla", "fr2.attachment_filename", "fr2.version_according_to_datetime", "fr2.program_according_to_full_report", "fr2.date"],
|
||||||
|
"Plans": [
|
||||||
|
{
|
||||||
|
"Node Type": "Seq Scan",
|
||||||
|
"Parent Relationship": "Outer",
|
||||||
|
"Parallel Aware": false,
|
||||||
|
"Relation Name": "foutrapport",
|
||||||
|
"Schema": "public",
|
||||||
|
"Alias": "fr1",
|
||||||
|
"Startup Cost": 0.00,
|
||||||
|
"Total Cost": 6048.89,
|
||||||
|
"Plan Rows": 105489,
|
||||||
|
"Plan Width": 419,
|
||||||
|
"Output": ["fr1.id", "fr1.program", "fr1.version", "fr1.lic_bedrijf", "fr1.lic_plaats", "fr1.lic_number", "fr1.callstack_crc_1", "fr1.callstack_crc_2", "fr1.callstack_crc_3", "fr1.exception_class", "fr1.exception_message", "fr1.full_report", "fr1.screenshot_filename", "fr1.ts", "fr1.duplicate_of", "fr1.actief", "fr1.commentaar", "fr1.bugzilla", "fr1.attachment_filename", "fr1.version_according_to_datetime", "fr1.program_according_to_full_report", "fr1.date"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node Type": "Index Scan",
|
||||||
|
"Parent Relationship": "Inner",
|
||||||
|
"Parallel Aware": false,
|
||||||
|
"Scan Direction": "Forward",
|
||||||
|
"Index Name": "foutrapport_callstack_crc_2_idx",
|
||||||
|
"Relation Name": "foutrapport",
|
||||||
|
"Schema": "public",
|
||||||
|
"Alias": "fr2",
|
||||||
|
"Startup Cost": 0.42,
|
||||||
|
"Total Cost": 0.81,
|
||||||
|
"Plan Rows": 11,
|
||||||
|
"Plan Width": 419,
|
||||||
|
"Output": ["fr2.id", "fr2.program", "fr2.version", "fr2.lic_bedrijf", "fr2.lic_plaats", "fr2.lic_number", "fr2.callstack_crc_1", "fr2.callstack_crc_2", "fr2.callstack_crc_3", "fr2.exception_class", "fr2.exception_message", "fr2.full_report", "fr2.screenshot_filename", "fr2.ts", "fr2.duplicate_of", "fr2.actief", "fr2.commentaar", "fr2.bugzilla", "fr2.attachment_filename", "fr2.version_according_to_datetime", "fr2.program_according_to_full_report", "fr2.date"],
|
||||||
|
"Index Cond": "(fr2.callstack_crc_2 = fr1.callstack_crc_2)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]")__json__";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Json::Value root; // will contains the root value after parsing.
|
||||||
|
Json::Reader reader;
|
||||||
|
bool parsingSuccessful = reader.parse(input, root);
|
||||||
|
ASSERT_TRUE(parsingSuccessful);
|
||||||
|
auto explain = ExplainRoot::createFromJson(root);
|
||||||
|
|
||||||
|
ASSERT_TRUE(explain != nullptr);
|
||||||
|
}
|
||||||
73
tests/auto/mycase/tst_PasswordManager.h
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "PasswordManager.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
|
||||||
|
TEST(PasswordManager, initial_changeMasterPassword_returns_true)
|
||||||
|
{
|
||||||
|
PasswordManager pwm;
|
||||||
|
|
||||||
|
auto res = pwm.changeMasterPassword("", "my test passphrase");
|
||||||
|
ASSERT_NO_THROW( res.get() );
|
||||||
|
ASSERT_THAT( res.get(), Eq(true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PasswordManager, unlock_succeeds)
|
||||||
|
{
|
||||||
|
PasswordManager pwm;
|
||||||
|
|
||||||
|
std::string passphrase = "my test passphrase";
|
||||||
|
|
||||||
|
auto res = pwm.changeMasterPassword("", passphrase);
|
||||||
|
ASSERT_NO_THROW( res.get() );
|
||||||
|
ASSERT_THAT( res.get(), Eq(true) );
|
||||||
|
|
||||||
|
auto res2 = pwm.unlock(passphrase);
|
||||||
|
ASSERT_NO_THROW( res2.get() );
|
||||||
|
ASSERT_THAT( res2.get(), Eq(true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PasswordManager, unlock_fails)
|
||||||
|
{
|
||||||
|
PasswordManager pwm;
|
||||||
|
|
||||||
|
std::string passphrase = "my test passphrase";
|
||||||
|
|
||||||
|
auto res = pwm.changeMasterPassword("", passphrase);
|
||||||
|
ASSERT_NO_THROW( res.get() );
|
||||||
|
ASSERT_THAT( res.get(), Eq(true) );
|
||||||
|
|
||||||
|
auto res2 = pwm.unlock(passphrase + "2");
|
||||||
|
ASSERT_NO_THROW( res2.get() );
|
||||||
|
ASSERT_THAT( res2.get(), Eq(false) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PasswordManager, test_save_get)
|
||||||
|
{
|
||||||
|
PasswordManager pwm;
|
||||||
|
|
||||||
|
std::string passphrase = "my test passphrase";
|
||||||
|
|
||||||
|
auto res = pwm.changeMasterPassword("", passphrase);
|
||||||
|
ASSERT_NO_THROW( res.get() );
|
||||||
|
ASSERT_THAT( res.get(), Eq(true) );
|
||||||
|
|
||||||
|
// auto res2 = pwm.unlock(passphrase + "2");
|
||||||
|
// ASSERT_NO_THROW( res2.get() );
|
||||||
|
// ASSERT_THAT( res2.get(), Eq(false) );
|
||||||
|
|
||||||
|
const std::string password = "password123";
|
||||||
|
const std::string key = "abc";
|
||||||
|
|
||||||
|
auto res2 = pwm.savePassword(key, password);
|
||||||
|
ASSERT_THAT( res2.valid(), Eq(true) );
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
auto res3 = pwm.getPassword(key, result);
|
||||||
|
ASSERT_THAT( res3.valid(), Eq(true) );
|
||||||
|
ASSERT_THAT( res3.get(), Eq(true) );
|
||||||
|
ASSERT_THAT( result, Eq(password) );
|
||||||
|
|
||||||
|
}
|
||||||
38
tests/auto/mycase/tst_SqlLexer.h
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "SqlLexer.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SqlLexer, lexer)
|
||||||
|
{
|
||||||
|
QString input = " SELECT ";
|
||||||
|
SqlLexer lexer(input, LexerState::Null);
|
||||||
|
|
||||||
|
int startpos, length;
|
||||||
|
BasicTokenType tokentype;
|
||||||
|
QString out;
|
||||||
|
lexer.nextBasicToken(startpos, length, tokentype, out);
|
||||||
|
|
||||||
|
ASSERT_THAT(startpos, Eq(1));
|
||||||
|
ASSERT_THAT(length, Eq(6));
|
||||||
|
ASSERT_THAT(tokentype, Eq(BasicTokenType::Symbol));
|
||||||
|
ASSERT_THAT( out, Eq(QString("SELECT")) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SqlLexer, lexer_quote_in_string)
|
||||||
|
{
|
||||||
|
QString input = " 'abc''def' ";
|
||||||
|
SqlLexer lexer(input, LexerState::Null);
|
||||||
|
|
||||||
|
int startpos, length;
|
||||||
|
BasicTokenType tokentype;
|
||||||
|
QString out;
|
||||||
|
lexer.nextBasicToken(startpos, length, tokentype, out);
|
||||||
|
|
||||||
|
ASSERT_THAT(startpos, Eq(1));
|
||||||
|
ASSERT_THAT(length, Eq(10));
|
||||||
|
ASSERT_THAT(tokentype, Eq(BasicTokenType::QuotedString));
|
||||||
|
}
|
||||||
|
|
||||||
203
tests/auto/mycase/tst_expected.h
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "Expected.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
Expected<int> getAnswerToEverything() { return 42; }
|
||||||
|
|
||||||
|
TEST(expected, valid_when_valid_returns_true)
|
||||||
|
{
|
||||||
|
Expected<int> v = getAnswerToEverything();
|
||||||
|
ASSERT_THAT(v.valid(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, get_when_valid_returns_value)
|
||||||
|
{
|
||||||
|
Expected<int> v = getAnswerToEverything();
|
||||||
|
ASSERT_THAT(v.get(), Eq(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, hasException_when_valid_returns_false)
|
||||||
|
{
|
||||||
|
Expected<int> v = getAnswerToEverything();
|
||||||
|
ASSERT_THAT(v.hasException<std::exception>(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromException_is_not_valid)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.valid(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromException_get_thows)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THROW (e.get(), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromException_has_exception_true)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.hasException<std::runtime_error>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromException_has_exception_false)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.hasException<std::logic_error>(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromException_has_derived_exception)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_is_valid)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
||||||
|
ASSERT_THAT(e.valid(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_get)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
||||||
|
ASSERT_THAT(e.get(), Eq(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_E_is_not_valid)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
|
ASSERT_THAT(e.valid(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_E_get_thows)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
|
ASSERT_THROW (e.get(), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_E_has_exception_true)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
|
ASSERT_THAT(e.hasException<std::runtime_error>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_E_has_exception_false)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
|
ASSERT_THAT(e.hasException<std::logic_error>(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromCode_E_has_derived_exception)
|
||||||
|
{
|
||||||
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
|
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Expected<int> getIntWithStdRuntimeError() { return Expected<void>(); }
|
||||||
|
|
||||||
|
Expected<void> getNothing() { return Expected<void>(); }
|
||||||
|
|
||||||
|
|
||||||
|
TEST(expected_void, valid_when_valid_returns_true)
|
||||||
|
{
|
||||||
|
Expected<void> v = getNothing();
|
||||||
|
ASSERT_THAT(v.valid(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, get_when_valid_returns_value)
|
||||||
|
{
|
||||||
|
Expected<void> v = getNothing();
|
||||||
|
ASSERT_NO_THROW(v.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, hasException_when_valid_returns_false)
|
||||||
|
{
|
||||||
|
Expected<void> v = getNothing();
|
||||||
|
ASSERT_THAT(v.hasException<std::exception>(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromException_is_not_valid)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.valid(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromException_get_thows)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THROW (e.get(), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromException_has_exception_true)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.hasException<std::runtime_error>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromException_has_exception_false)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.hasException<std::logic_error>(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromException_has_derived_exception)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
||||||
|
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_is_valid)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode([]() -> void { });
|
||||||
|
ASSERT_THAT(e.valid(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_get)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode([]() -> void { });
|
||||||
|
ASSERT_NO_THROW(e.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void expected_void_throws_func()
|
||||||
|
{
|
||||||
|
throw std::runtime_error("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_E_is_not_valid)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
||||||
|
ASSERT_THAT(e.valid(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_E_get_thows)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
||||||
|
ASSERT_THROW (e.get(), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_E_has_exception_true)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
||||||
|
ASSERT_THAT(e.hasException<std::runtime_error>(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_E_has_exception_false)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
||||||
|
ASSERT_THAT(e.hasException<std::logic_error>(), Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, void_fromCode_E_has_derived_exception)
|
||||||
|
{
|
||||||
|
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
||||||
|
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
||||||
|
}
|
||||||
63
tests/auto/mycase/tst_scopeguard.h
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "ScopeGuard.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ScopeGuard, normal_run_fun_on_destruction_1)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
auto sg = scopeGuard([&result]() { result = true; });
|
||||||
|
ASSERT_THAT(result, Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopeGuard, normal_run_fun_on_destruction_2)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
{
|
||||||
|
auto sg = scopeGuard([&result]() { result = true; });
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopeGuard, dismiss)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
{
|
||||||
|
auto sg = scopeGuard([&result]() { result = true; });
|
||||||
|
sg.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_THAT(result, Eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopeGuard, SCOPE_EXIT_macro_1)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
{
|
||||||
|
SCOPE_EXIT { result = true; };
|
||||||
|
ASSERT_THAT(result, Eq(false)); // prove previous statement hasn't run yet
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopeGuard, SCOPE_EXIT_macro_2)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
{
|
||||||
|
SCOPE_EXIT { result = true; };
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_THAT(result, Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TEST(expected, get_when_valid_returns_value)
|
||||||
|
//{
|
||||||
|
// Expected<int> v = getAnswerToEverything();
|
||||||
|
// ASSERT_THAT(v.get(), Eq(42));
|
||||||
|
//}
|
||||||
|
|
||||||
9
tests/mygtestutils/PrintTo_Qt.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "PrintTo_Qt.h"
|
||||||
|
|
||||||
|
void PrintTo(const QDateTime &dt, ::std::ostream* os) {
|
||||||
|
*os << dt.toString(Qt::ISODateWithMs).toUtf8().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTo(const QString &s, ::std::ostream* os) {
|
||||||
|
*os << s.toUtf8().toStdString();
|
||||||
|
}
|
||||||
11
tests/mygtestutils/PrintTo_Qt.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef PRINTTO_QT_H
|
||||||
|
#define PRINTTO_QT_H
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
void PrintTo(const QDateTime &dt, ::std::ostream* os);
|
||||||
|
void PrintTo(const QString &s, ::std::ostream* os);
|
||||||
|
|
||||||
|
#endif // PRINTTO_QT_H
|
||||||
32
tests/mygtestutils/mygtestutils.pro
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2017-12-01T10:07:31
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
TARGET = mygtestutils
|
||||||
|
TEMPLATE = lib
|
||||||
|
CONFIG += staticlib
|
||||||
|
|
||||||
|
# The following define makes your compiler emit warnings if you use
|
||||||
|
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||||
|
# depend on your compiler). Please consult the documentation of the
|
||||||
|
# deprecated API in order to know how to port your code away from it.
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
|
|
||||||
|
# You can also make your code fail to compile if you use deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
PrintTo_Qt.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
PrintTo_Qt.h
|
||||||
|
unix {
|
||||||
|
target.path = /usr/lib
|
||||||
|
INSTALLS += target
|
||||||
|
}
|
||||||
5
tests/tests.pro
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
SUBDIRS += auto \
|
||||||
|
PgsqlTests \
|
||||||
|
mygtestutils
|
||||||