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 \
|
||||
CsvWriter.cpp \
|
||||
BackupFormatModel.cpp \
|
||||
QueuedBackgroundTask.cpp
|
||||
QueuedBackgroundTask.cpp \
|
||||
ExplainTreeModelItem.cpp \
|
||||
jsoncpp.cpp
|
||||
|
||||
HEADERS += PasswordManager.h \
|
||||
SqlLexer.h \
|
||||
|
|
@ -39,9 +41,12 @@ HEADERS += PasswordManager.h \
|
|||
CsvWriter.h \
|
||||
BackupFormatModel.h \
|
||||
QueuedBackgroundTask.h \
|
||||
Expected.h
|
||||
Expected.h \
|
||||
ExplainTreeModelItem.h
|
||||
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
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 "PgDatabaseContainer.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
#include "ResultTableModelUtil.h"
|
||||
|
||||
using namespace Pgsql;
|
||||
|
||||
DatabasesTableModel::DatabasesTableModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
: BaseTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +62,7 @@ QVariant DatabasesTableModel::headerData(int section, Qt::Orientation orientatio
|
|||
return v;
|
||||
}
|
||||
|
||||
int DatabasesTableModel::rowCount(const QModelIndex &parent) const
|
||||
int DatabasesTableModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
int result = 0;
|
||||
if (m_databases) {
|
||||
|
|
@ -68,62 +71,79 @@ int DatabasesTableModel::rowCount(const QModelIndex &parent) const
|
|||
return result;
|
||||
}
|
||||
|
||||
int DatabasesTableModel::columnCount(const QModelIndex &parent) const
|
||||
int DatabasesTableModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
int result = 10;
|
||||
// if (parent.isValid())
|
||||
// return 10;
|
||||
int result = COL_COUNT;
|
||||
|
||||
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;
|
||||
//if (!index.isValid())
|
||||
if (m_databases) {
|
||||
const PgDatabase &db = m_databases->getByIdx(index.row());
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (index.column()) {
|
||||
case NameCol:
|
||||
v = db.name;
|
||||
break;
|
||||
case DbaCol:
|
||||
// todo lookup role name
|
||||
{
|
||||
const auto& roles = m_catalog->authIds();
|
||||
v = QString("%1 (%2)").arg(roles->getByOid(db.dba).name).arg(db.dba);
|
||||
}
|
||||
break;
|
||||
case EncodingCol:
|
||||
// todo lookup encoding name
|
||||
v = db.encoding;
|
||||
break;
|
||||
case CollateCol:
|
||||
v = db.collate;
|
||||
break;
|
||||
case CTypeCol:
|
||||
v = db.ctype;
|
||||
break;
|
||||
case IsTemplateCol:
|
||||
v = db.isTemplate;
|
||||
break;
|
||||
case AllowConnCol:
|
||||
v = db.allowConn;
|
||||
break;
|
||||
case ConnLimitCol:
|
||||
v = db.connLimit;
|
||||
break;
|
||||
case TablespaceCol:
|
||||
// todo lookup tablespace name
|
||||
v = db.tablespace;
|
||||
break;
|
||||
case AclCol:
|
||||
v = db.acl;
|
||||
break;
|
||||
}
|
||||
switch (index.column()) {
|
||||
case NameCol:
|
||||
v = db.name;
|
||||
break;
|
||||
case DbaCol:
|
||||
v = getRoleDisplayString(m_catalog, db.dba);
|
||||
break;
|
||||
case EncodingCol:
|
||||
// todo lookup encoding name
|
||||
v = db.encoding;
|
||||
break;
|
||||
case CollateCol:
|
||||
v = db.collate;
|
||||
break;
|
||||
case CTypeCol:
|
||||
v = db.ctype;
|
||||
break;
|
||||
case IsTemplateCol:
|
||||
v = db.isTemplate;
|
||||
break;
|
||||
case AllowConnCol:
|
||||
v = db.allowConn;
|
||||
break;
|
||||
case ConnLimitCol:
|
||||
v = db.connLimit;
|
||||
break;
|
||||
case TablespaceCol:
|
||||
// todo lookup tablespace name
|
||||
v = db.tablespace;
|
||||
break;
|
||||
case AclCol:
|
||||
v = db.acl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef DATABASESTABLEMODEL_H
|
||||
#ifndef DATABASESTABLEMODEL_H
|
||||
#define DATABASESTABLEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include "BaseTableModel.h"
|
||||
|
||||
class PgDatabaseContainer;
|
||||
class PgDatabaseCatalogue;
|
||||
|
|
@ -9,14 +9,14 @@ class PgDatabaseCatalogue;
|
|||
/** Class for displaying the list of databases of a server in a QTableView
|
||||
*
|
||||
*/
|
||||
class DatabasesTableModel : public QAbstractTableModel
|
||||
class DatabasesTableModel : public BaseTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum e_Columns : int { NameCol, DbaCol, EncodingCol, CollateCol,
|
||||
CTypeCol, IsTemplateCol, AllowConnCol, ConnLimitCol,
|
||||
TablespaceCol, AclCol };
|
||||
TablespaceCol, AclCol, COL_COUNT };
|
||||
|
||||
|
||||
|
||||
|
|
@ -31,7 +31,10 @@ public:
|
|||
int rowCount(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:
|
||||
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 "PgDatabaseContainer.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid)
|
||||
{
|
||||
QString name;
|
||||
const PgAuthIdContainer *auth_ids = cat->authIds();
|
||||
auto auth_ids = cat->authIds();
|
||||
if (auth_ids) {
|
||||
const PgAuthId& auth_id = auth_ids->getByOid(oid);
|
||||
if (auth_id.valid()) {
|
||||
|
|
@ -18,6 +18,13 @@ QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid)
|
|||
return name;
|
||||
}
|
||||
|
||||
QString getRoleDisplayString(const PgDatabaseCatalogue *cat, Oid oid)
|
||||
{
|
||||
QString name = getRoleNameFromOid(cat, oid);
|
||||
return QString("%1 (%2)").arg(name).arg(oid);
|
||||
}
|
||||
|
||||
|
||||
PgDatabaseCatalogue::PgDatabaseCatalogue()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,5 +45,7 @@ private:
|
|||
};
|
||||
|
||||
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid);
|
||||
QString getRoleDisplayString(const PgDatabaseCatalogue *cat, Oid oid);
|
||||
|
||||
|
||||
#endif // PGSQLDATABASECATALOGUE_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "PgDatabaseContainer.h"
|
||||
#include "PgDatabaseContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
PgDatabaseContainer::PgDatabaseContainer(PgDatabaseCatalogue *cat)
|
||||
: PgContainer<PgDatabase>(cat)
|
||||
|
|
@ -17,18 +18,21 @@ void PgDatabaseContainer::load(const Pgsql::Result &res)
|
|||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
for (auto row : res) {
|
||||
Pgsql::Col col(row);
|
||||
PgDatabase v;
|
||||
v.oid << row.get(0); // InvalidOid;
|
||||
v.name << row.get(1);
|
||||
v.dba << row.get(2); // owner?
|
||||
v.encoding << row.get(3);
|
||||
v.collate << row.get(4);
|
||||
v.ctype << row.get(5);
|
||||
v.isTemplate << row.get(6);
|
||||
v.allowConn << row.get(7);
|
||||
v.connLimit << row.get(8);
|
||||
v.tablespace << row.get(9);
|
||||
v.acl << row.get(10);
|
||||
// v.oid << row.get(0); // InvalidOid;
|
||||
// v.name << row.get(1);
|
||||
// v.dba << row.get(2); // owner?
|
||||
// v.encoding << row.get(3);
|
||||
// v.collate << row.get(4);
|
||||
// v.ctype << row.get(5);
|
||||
// v.isTemplate << row.get(6);
|
||||
// v.allowConn << row.get(7);
|
||||
// v.connLimit << row.get(8);
|
||||
// v.tablespace << row.get(9);
|
||||
// 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);
|
||||
}
|
||||
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_ColumnLoops = 5;
|
||||
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)
|
||||
: QAbstractItemModel(parent)
|
||||
|
|
@ -26,7 +27,7 @@ QVariant QueryExplainModel::data(const QModelIndex &index, int role) const
|
|||
if (role == Qt::DisplayRole) {
|
||||
switch (col) {
|
||||
case c_ColumnNode:
|
||||
result = item->nodeType();
|
||||
result = item->nodeType;
|
||||
break;
|
||||
case c_ColumnExclusive:
|
||||
result = item->exclusiveTime();
|
||||
|
|
@ -38,14 +39,17 @@ if (role == Qt::DisplayRole) {
|
|||
result = item->estimateError();
|
||||
break;
|
||||
case c_ColumnRowCount:
|
||||
result = item->actualRows();
|
||||
result = item->actualRows;
|
||||
break;
|
||||
case c_ColumnLoops:
|
||||
result = item->actualLoops();
|
||||
result = item->actualLoops;
|
||||
break;
|
||||
case c_ColumnDetails:
|
||||
result = item->detailString();
|
||||
break;
|
||||
case c_ColumnShared:
|
||||
result = item->sharedBlocks.asString();
|
||||
break;
|
||||
} // end switch column
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole) {
|
||||
|
|
@ -133,6 +137,9 @@ QVariant QueryExplainModel::headerData(int section, Qt::Orientation orientation,
|
|||
case c_ColumnDetails:
|
||||
v = "Details";
|
||||
break;
|
||||
case c_ColumnShared:
|
||||
v = "Shared";
|
||||
break;
|
||||
}
|
||||
}
|
||||
// else if (role == Qt::SizeHintRole) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "QueryResultModel.h"
|
||||
#include "ResultTableModelUtil.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
|
|
@ -36,7 +37,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
|||
Oid o = result->type(col);
|
||||
QString s(result->val(col, rij));
|
||||
switch (o) {
|
||||
case oid_bool:
|
||||
case BOOLOID:
|
||||
s = (s == "t") ? "TRUE" : "FALSE";
|
||||
// intentional fall through
|
||||
default:
|
||||
|
|
@ -50,23 +51,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
|||
}
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole) {
|
||||
Oid o = 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;
|
||||
}
|
||||
r = GetDefaultAlignmentForType(result->type(col));
|
||||
}
|
||||
else if (role == Qt::ForegroundRole) {
|
||||
if (result->null(col, rij)) {
|
||||
|
|
@ -75,19 +60,19 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
|
|||
else {
|
||||
Oid o = result->type(col);
|
||||
switch (o) {
|
||||
case oid_int2:
|
||||
case oid_int4:
|
||||
case oid_int8:
|
||||
case INT2OID:
|
||||
case INT4OID:
|
||||
case INT8OID:
|
||||
r = QBrush(Qt::darkBlue);
|
||||
break;
|
||||
case oid_float4:
|
||||
case oid_float8:
|
||||
case FLOAT4OID:
|
||||
case FLOAT8OID:
|
||||
r = QBrush(Qt::darkCyan);
|
||||
break;
|
||||
case oid_numeric:
|
||||
case NUMERICOID:
|
||||
r = QBrush(Qt::darkGreen);
|
||||
break;
|
||||
case oid_bool:
|
||||
case BOOLOID:
|
||||
if (strcmp(result->val(col, rij), "t") == 0) {
|
||||
r = QBrush(Qt::darkGreen);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "QueryTab.h"
|
||||
#include "QueryTab.h"
|
||||
#include "ui_QueryTab.h"
|
||||
#include "SqlSyntaxHighlighter.h"
|
||||
#include <QStandardPaths>
|
||||
|
|
@ -229,30 +229,32 @@ void QueryTab::explain(bool analyze)
|
|||
|
||||
std::string analyze_str;
|
||||
if (analyze) {
|
||||
analyze_str = "ANALYZE, ";
|
||||
analyze_str = "ANALYZE, BUFFERS, ";
|
||||
}
|
||||
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,
|
||||
[this](Expected<std::shared_ptr<Pgsql::Result>> exp_res, qint64 )
|
||||
{
|
||||
if (exp_res.valid()) {
|
||||
// Process explain data seperately
|
||||
auto res = exp_res.get();
|
||||
std::thread([this,res]()
|
||||
{
|
||||
std::shared_ptr<ExplainRoot> explain;
|
||||
if (res->cols() == 1 && res->rows() == 1) {
|
||||
std::string s = res->val(0, 0);
|
||||
Json::Value root; // will contains the root value after parsing.
|
||||
Json::Reader reader;
|
||||
bool parsingSuccessful = reader.parse(s, root);
|
||||
if (parsingSuccessful) {
|
||||
explain = ExplainRoot::createFromJson(root);
|
||||
if (res) {
|
||||
std::thread([this,res]()
|
||||
{
|
||||
std::shared_ptr<ExplainRoot> explain;
|
||||
if (res->cols() == 1 && res->rows() == 1) {
|
||||
std::string s = res->val(0, 0);
|
||||
Json::Value root; // will contains the root value after parsing.
|
||||
Json::Reader reader;
|
||||
bool parsingSuccessful = reader.parse(s, root);
|
||||
if (parsingSuccessful) {
|
||||
explain = ExplainRoot::createFromJson(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_win->QueueTask([this, explain]() { explain_ready(explain); });
|
||||
}).detach();
|
||||
m_win->QueueTask([this, explain]() { explain_ready(explain); });
|
||||
}).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"
|
||||
|
||||
RolesTableModel::RolesTableModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
: BaseTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -74,50 +74,80 @@ int RolesTableModel::columnCount(const QModelIndex &parent) const
|
|||
return result;
|
||||
}
|
||||
|
||||
QVariant RolesTableModel::data(const QModelIndex &index, int role) const
|
||||
Oid RolesTableModel::getType(int column) const
|
||||
{
|
||||
QVariant v;
|
||||
//if (!index.isValid())
|
||||
if (m_roles) {
|
||||
const PgAuthId &authid = m_roles->getByIdx(index.row());
|
||||
if (role == Qt::DisplayRole) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
using namespace Pgsql;
|
||||
|
||||
Oid oid;
|
||||
switch (column) {
|
||||
case NameCol:
|
||||
oid = VARCHAROID;
|
||||
break;
|
||||
|
||||
case ReplicationCol:
|
||||
case BypassRlsCol:
|
||||
case CanLoginCol:
|
||||
case CreateDBCol:
|
||||
case CreateRoleCol:
|
||||
case InheritCol:
|
||||
case SuperCol:
|
||||
oid = BOOLOID;
|
||||
break;
|
||||
|
||||
case ConnlimitCol:
|
||||
oid = INT4OID;
|
||||
break;
|
||||
|
||||
case ValidUntilCol:
|
||||
oid = TIMESTAMPOID;
|
||||
break;
|
||||
default:
|
||||
oid = InvalidOid;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
#define ROLESTABLEMODEL_H
|
||||
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include "BaseTableModel.h"
|
||||
|
||||
class PgAuthIdContainer;
|
||||
|
||||
/** Class for displaying the list of roles of a server in a QTableView
|
||||
*
|
||||
*/
|
||||
class RolesTableModel : public QAbstractTableModel {
|
||||
class RolesTableModel : public BaseTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum e_Columns : int { NameCol, SuperCol, InheritCol, CreateRoleCol,
|
||||
|
|
@ -29,7 +29,10 @@ public:
|
|||
int rowCount(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:
|
||||
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
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
||||
|
|
@ -13,7 +13,7 @@ TARGET = pglab
|
|||
TEMPLATE = app
|
||||
|
||||
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:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
|
||||
|
||||
|
|
@ -29,9 +29,7 @@ win32:RC_ICONS += pglab.ico
|
|||
|
||||
SOURCES += main.cpp\
|
||||
QueryResultModel.cpp \
|
||||
jsoncpp.cpp \
|
||||
QueryExplainModel.cpp \
|
||||
ExplainTreeModelItem.cpp \
|
||||
ASyncDBConnection.cpp \
|
||||
tsqueue.cpp \
|
||||
DatabaseWindow.cpp \
|
||||
|
|
@ -68,12 +66,13 @@ PgDatabaseCatalogue.cpp \
|
|||
ConnectionList.cpp \
|
||||
ProcessStdioWidget.cpp \
|
||||
GlobalIoService.cpp \
|
||||
CodeBuilderConfiguration.cpp
|
||||
CodeBuilderConfiguration.cpp \
|
||||
ResultTableModelUtil.cpp \
|
||||
BaseTableModel.cpp
|
||||
|
||||
HEADERS += \
|
||||
QueryResultModel.h \
|
||||
QueryExplainModel.h \
|
||||
ExplainTreeModelItem.h \
|
||||
ASyncDBConnection.h \
|
||||
tsqueue.h \
|
||||
DatabaseWindow.h \
|
||||
|
|
@ -110,7 +109,9 @@ PgDatabaseCatalogue.h \
|
|||
ConnectionList.h \
|
||||
ProcessStdioWidget.h \
|
||||
GlobalIoService.h \
|
||||
CodeBuilderConfiguration.h
|
||||
CodeBuilderConfiguration.h \
|
||||
ResultTableModelUtil.h \
|
||||
BaseTableModel.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
DatabaseWindow.ui \
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/server_delete.png</file>
|
||||
<file>icons/server_go.png</file>
|
||||
<file>icons/script_delete.png</file>
|
||||
<file>icons/script_go.png</file>
|
||||
<file>icons/folder.png</file>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ TEMPLATE = subdirs
|
|||
|
||||
DEFINES += BOOST_ENABLE_ASSERT_HANDLER
|
||||
|
||||
|
||||
SUBDIRS += core \
|
||||
pgsql \
|
||||
pglab
|
||||
pglab
|
||||
|
||||
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.
|
||||
*/
|
||||
void addText(const char *data, Oid oid=oid_varchar);
|
||||
void add(const QString &s, Oid oid=oid_varchar);
|
||||
void addText(const char *data, Oid oid=VARCHAROID);
|
||||
void add(const QString &s, Oid oid=VARCHAROID);
|
||||
void addBinary(const char *data, int length, Oid oid);
|
||||
void clear();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ namespace Pgsql {
|
|||
Value get(int col) const;
|
||||
//Value get(const char *colname) const;
|
||||
//bool get(int col, QString &s);
|
||||
|
||||
|
||||
private:
|
||||
const Result& m_result;
|
||||
int m_row;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
using namespace Pgsql;
|
||||
|
||||
Value::Value(const char *val, Oid typ)
|
||||
: m_val(val), m_typ(typ)
|
||||
: m_val(val)
|
||||
, m_typ(typ)
|
||||
{}
|
||||
|
||||
QString Value::asQString() const
|
||||
|
|
@ -15,15 +16,30 @@ QString Value::asQString() 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
|
||||
{
|
||||
return QDateTime::fromString(asQString(),
|
||||
"yyyy-MM-dd hh:mm:ss");
|
||||
return QDateTime::fromString(asQString(), Qt::ISODateWithMs);
|
||||
// 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
|
||||
{
|
||||
return m_val;
|
||||
|
|
@ -54,6 +70,14 @@ Value::operator bool() const
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -17,12 +17,17 @@ namespace Pgsql {
|
|||
|
||||
operator QString() const;
|
||||
operator QDateTime() const;
|
||||
operator QDate() const;
|
||||
operator QTime() const;
|
||||
operator std::string() const;
|
||||
operator short() const;
|
||||
operator int() const;
|
||||
operator Oid() const;
|
||||
operator long long() const;
|
||||
operator bool() const;
|
||||
|
||||
bool isString() const;
|
||||
|
||||
private:
|
||||
const char *m_val;
|
||||
Oid m_typ;
|
||||
|
|
|
|||
|
|
@ -5,15 +5,95 @@
|
|||
|
||||
namespace Pgsql {
|
||||
|
||||
const Oid oid_bool = 16;
|
||||
const Oid oid_int2 = 21;
|
||||
const Oid oid_int4 = 23;
|
||||
const Oid oid_int8 = 20;
|
||||
const Oid oid_float4 = 700;
|
||||
const Oid oid_float8 = 701;
|
||||
const Oid oid_numeric = 1700;
|
||||
const Oid oid_oid = 26;
|
||||
const Oid oid_varchar = 1043;
|
||||
const Oid BOOLOID = 16;
|
||||
const Oid BYTEAOID = 17;
|
||||
const Oid CHAROID = 18;
|
||||
const Oid NAMEOID = 19;
|
||||
const Oid INT8OID = 20;
|
||||
const Oid INT2OID = 21;
|
||||
const Oid INT2VECTOROID = 22;
|
||||
const Oid INT4OID = 23;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
|||
TARGET = pgsql
|
||||
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
|
||||
#LIBS += -LC:/prog/boost/lib -Lc:/prog/lib libpq.lib fmt.lib User32.lib ws2_32.lib
|
||||
LIBS += -LC:/PROG/LIB -lws2_32 -llibpq
|
||||
|
|
@ -31,14 +34,16 @@ SOURCES += Pgsql_Connection.cpp \
|
|||
Pgsql_Params.cpp \
|
||||
Pgsql_Result.cpp \
|
||||
Pgsql_Row.cpp \
|
||||
Pgsql_Value.cpp
|
||||
Pgsql_Value.cpp \
|
||||
Pgsql_Col.cpp
|
||||
|
||||
HEADERS += Pgsql_Connection.h \
|
||||
Pgsql_Params.h \
|
||||
Pgsql_Result.h \
|
||||
Pgsql_Row.h \
|
||||
Pgsql_Value.h \
|
||||
Pgsql_declare.h
|
||||
Pgsql_declare.h \
|
||||
Pgsql_Col.h
|
||||
|
||||
#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
|
||||