From 3a13b7ffb409d8afba6b25c857c1be8d844fcb31 Mon Sep 17 00:00:00 2001 From: eelke Date: Sat, 9 Dec 2017 10:45:13 +0100 Subject: [PATCH] Messy commit. Testing suff and some improvements to how data is shown. --- core/ExplainTreeModelItem.cpp | 409 ++++++++++++++++++++ core/ExplainTreeModelItem.h | 163 ++++++++ core/core.pro | 9 +- {pglab => core}/json/json-forwards.h | 0 {pglab => core}/json/json.h | 0 {pglab => core}/jsoncpp.cpp | 0 pglab/BaseTableModel.cpp | 36 ++ pglab/BaseTableModel.h | 21 + pglab/DatabasesTableModel.cpp | 116 +++--- pglab/DatabasesTableModel.h | 13 +- pglab/ExplainTreeModelItem.cpp | 384 ------------------ pglab/ExplainTreeModelItem.h | 144 ------- pglab/PgDatabaseCatalogue.cpp | 11 +- pglab/PgDatabaseCatalogue.h | 2 + pglab/PgDatabaseContainer.cpp | 28 +- pglab/QueryExplainModel.cpp | 15 +- pglab/QueryResultModel.cpp | 35 +- pglab/QueryTab.cpp | 34 +- pglab/ResultTableModelUtil.cpp | 57 +++ pglab/ResultTableModelUtil.h | 23 ++ pglab/RolesTableModel.cpp | 116 ++++-- pglab/RolesTableModel.h | 9 +- pglab/icons/about.png | Bin 436 -> 2112 bytes pglab/icons/add_connection.png | Bin 416 -> 1480 bytes pglab/icons/backup_database.png | Bin 471 -> 2377 bytes pglab/icons/delete_connection.png | Bin 473 -> 1497 bytes pglab/icons/manage_server.png | Bin 618 -> 1495 bytes pglab/icons/new_query_tab.png | Bin 419 -> 1272 bytes pglab/icons/open_query_window.png | Bin 525 -> 1339 bytes pglab/pglab.pro | 15 +- pglab/resources.qrc | 1 - pglabAll.pro | 5 +- pgsql/Pgsql_Col.cpp | 2 + pgsql/Pgsql_Col.h | 39 ++ pgsql/Pgsql_Params.h | 4 +- pgsql/Pgsql_Row.h | 2 + pgsql/Pgsql_Value.cpp | 32 +- pgsql/Pgsql_Value.h | 5 + pgsql/Pgsql_declare.h | 98 ++++- pgsql/pgsql.pro | 11 +- tests/PgsqlTests/.gitignore | 73 ++++ tests/PgsqlTests/PgsqlTests.pro | 43 ++ tests/PgsqlTests/gtest_dependency.pri | 29 ++ tests/PgsqlTests/main.cpp | 7 + tests/PgsqlTests/tst_Value.cpp | 66 ++++ tests/auto/auto.pro | 3 + tests/auto/gtest_dependency.pri | 29 ++ tests/auto/mycase/main.cpp | 13 + tests/auto/mycase/mycase.pro | 32 ++ tests/auto/mycase/tst_CsvWriter.h | 113 ++++++ tests/auto/mycase/tst_ExplainJsonParser.cpp | 80 ++++ tests/auto/mycase/tst_PasswordManager.h | 73 ++++ tests/auto/mycase/tst_SqlLexer.h | 38 ++ tests/auto/mycase/tst_expected.h | 203 ++++++++++ tests/auto/mycase/tst_scopeguard.h | 63 +++ tests/mygtestutils/PrintTo_Qt.cpp | 9 + tests/mygtestutils/PrintTo_Qt.h | 11 + tests/mygtestutils/mygtestutils.pro | 32 ++ tests/tests.pro | 5 + 59 files changed, 2045 insertions(+), 716 deletions(-) create mode 100644 core/ExplainTreeModelItem.cpp create mode 100644 core/ExplainTreeModelItem.h rename {pglab => core}/json/json-forwards.h (100%) rename {pglab => core}/json/json.h (100%) rename {pglab => core}/jsoncpp.cpp (100%) create mode 100644 pglab/BaseTableModel.cpp create mode 100644 pglab/BaseTableModel.h delete mode 100644 pglab/ExplainTreeModelItem.cpp delete mode 100644 pglab/ExplainTreeModelItem.h create mode 100644 pglab/ResultTableModelUtil.cpp create mode 100644 pglab/ResultTableModelUtil.h create mode 100644 pgsql/Pgsql_Col.cpp create mode 100644 pgsql/Pgsql_Col.h create mode 100644 tests/PgsqlTests/.gitignore create mode 100644 tests/PgsqlTests/PgsqlTests.pro create mode 100644 tests/PgsqlTests/gtest_dependency.pri create mode 100644 tests/PgsqlTests/main.cpp create mode 100644 tests/PgsqlTests/tst_Value.cpp create mode 100644 tests/auto/auto.pro create mode 100644 tests/auto/gtest_dependency.pri create mode 100644 tests/auto/mycase/main.cpp create mode 100644 tests/auto/mycase/mycase.pro create mode 100644 tests/auto/mycase/tst_CsvWriter.h create mode 100644 tests/auto/mycase/tst_ExplainJsonParser.cpp create mode 100644 tests/auto/mycase/tst_PasswordManager.h create mode 100644 tests/auto/mycase/tst_SqlLexer.h create mode 100644 tests/auto/mycase/tst_expected.h create mode 100644 tests/auto/mycase/tst_scopeguard.h create mode 100644 tests/mygtestutils/PrintTo_Qt.cpp create mode 100644 tests/mygtestutils/PrintTo_Qt.h create mode 100644 tests/mygtestutils/mygtestutils.pro create mode 100644 tests/tests.pro diff --git a/core/ExplainTreeModelItem.cpp b/core/ExplainTreeModelItem.cpp new file mode 100644 index 0000000..418eba7 --- /dev/null +++ b/core/ExplainTreeModelItem.cpp @@ -0,0 +1,409 @@ +#include "ExplainTreeModelItem.h" +#include "json/json.h" +#include + +namespace { + + ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan) + { + + const auto json_null = Json::Value::nullSingleton(); + ExplainTreeModelItemPtr result = std::make_shared(); + result->nodeType = QString::fromStdString(plan.get("Node Type", json_null).asString()); + result->parallelAware = plan.get("Parallel Aware", json_null).asBool(); + result->strategy = QString::fromStdString(plan.get("Strategy", json_null).asString()); + result->joinType = QString::fromStdString(plan.get("Join Type", json_null).asString()); + result->startupCost = plan.get("Startup Cost", json_null).asFloat(); + result->totalCost = plan.get("Total Cost", json_null).asFloat(); + result->estimatedRows = plan.get("Plan Rows", json_null).asInt(); + result->planWidth = plan.get("Plan Width", json_null).asInt(); + result->actualStartupTime = plan.get("Actual Startup Time", json_null).asFloat(); + result->actualTotalTime = plan.get("Actual Total Time", json_null).asFloat(); + result->actualRows = plan.get("Actual Rows", json_null).asInt(); + result->actualLoops = plan.get("Actual Loops", json_null).asInt(); + + result->relationName = QString::fromStdString(plan.get("Relation Name", json_null).asString()); + result->alias = QString::fromStdString(plan.get("Alias", json_null).asString()); + result->scanDirection = QString::fromStdString(plan.get("Scan Direction", json_null).asString()); + result->indexName = QString::fromStdString(plan.get("Index Name", json_null).asString()); + result->indexCondition = QString::fromStdString(plan.get("Index Cond", json_null).asString()); + result->indexRecheck = QString::fromStdString(plan.get("Rows Removed by Index Recheck", json_null).asString()); + result->filter = QString::fromStdString(plan.get("Filter", json_null).asString()); + result->hashCondition = QString::fromStdString(plan.get("Hash Cond", json_null).asString()); + + result->sortKey = QString::fromStdString(plan.get("Sort Key", json_null).toStyledString()); + result->sortMethod = QString::fromStdString(plan.get("Sort Method", json_null).asString()); + + result->sortSpaceUsed = plan.get("Sort Space Used", json_null).asInt(); + result->sortSpaceType = QString::fromStdString(plan.get("Sort Space Type", json_null).asString()); + + result->sharedBlocks.hit = plan.get("Shared Hit Blocks", json_null).asInt(); + result->sharedBlocks.read = plan.get("Shared Read Blocks", json_null).asInt(); + result->sharedBlocks.dirtied = plan.get("Shared Dirtied Blocks", json_null).asInt(); + result->sharedBlocks.written = plan.get("Shared Written Blocks", json_null).asInt(); + + result->localBlocks.hit = plan.get("Local Hit Blocks", json_null).asInt(); + result->localBlocks.read = plan.get("Local Read Blocks", json_null).asInt(); + result->localBlocks.dirtied = plan.get("Local Dirtied Blocks", json_null).asInt(); + result->localBlocks.written = plan.get("Local Written Blocks", json_null).asInt(); + + result->tempBlocks.read = plan.get("Temp Read Blocks", json_null).asInt(); + result->tempBlocks.written = plan.get("Temp Written Blocks", json_null).asInt(); + result->ioTimes.read = plan.get("I/O Read Time", json_null).asDouble(); + result->ioTimes.write = plan.get("I/O Write Time", json_null).asDouble(); + + Json::Value &plans = plan["Plans"]; + if (plans.isArray()) { + for (auto p : plans) { + result->appendChild( + createPlanItemFromJson(p)); + } + } + +// "Parallel Aware": false, + return result; + } + +} // END of unnamed namespace + +ExplainRoot::SPtr ExplainRoot::createFromJson(Json::Value &json) +{ + auto res = std::make_shared(); + // Explain always seems to be an array with one element + if (json.isArray()) { + if (json.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::infinity(); + } + } + else if (actualRows > estimatedRows) { + if (estimatedRows > 0) { + res = float(actualRows) / estimatedRows; + } + else { + res = std::numeric_limits::infinity(); + } + res = -res; + } + return res; +} + +QString ExplainTreeModelItem::detailString() const +{ + QString s; + if (!joinType.isEmpty()) { + s += joinType + " " + nodeType + " "; + } + if (!strategy.isEmpty()) { + s += strategy + " " + nodeType + " "; + } + if (!indexName.isEmpty()) { + s+= scanDirection + " " + + nodeType + "\n"; + if (!indexCondition.isEmpty()) { + s += "cond: " + indexCondition + " "; + } + if (!filter.isEmpty()) { + s += "filter: " + filter + "\n"; + } + if (!indexRecheck.isEmpty()) { + s += "removed by recheck: " + indexRecheck + "\n"; + } + s += "idx: " + indexName + " rel: " + alias + " "; + } + else { + if (!alias.isEmpty()) { + s += nodeType + " rel: " + alias + " "; + } + } + if (!hashCondition.isEmpty()) { + s += hashCondition + " "; + } + if (!sortMethod.isEmpty()) { + s += sortMethod + " " + sortSpaceType + " " + + QString::number(sortSpaceUsed) + "kB " + + sortKey + " "; + + } + + return s.trimmed(); +} + +//"Sort Key": ["pg_attribute.attname"], +//"Sort Method": "quicksort", +//"Sort Space Used": 1426, +//"Sort Space Type": "Memory", + + +//{ +// "Node Type": "Index Scan", +// "Parent Relationship": "Inner", +// "Scan Direction": "Forward", +// "Index Name": "pg_type_oid_index", +// "Relation Name": "pg_type", +// "Alias": "pg_type", +// "Startup Cost": 0.15, +// "Total Cost": 0.18, +// "Plan Rows": 1, +// "Plan Width": 758, +// "Actual Startup Time": 0.003, +// "Actual Total Time": 0.004, +// "Actual Rows": 1, +// "Actual Loops": 100, +// "Index Cond": "(oid = pg_attribute.atttypid)", +// "Rows Removed by Index Recheck": 0 +// "Filter": "actief" +//} diff --git a/core/ExplainTreeModelItem.h b/core/ExplainTreeModelItem.h new file mode 100644 index 0000000..30cdb7f --- /dev/null +++ b/core/ExplainTreeModelItem.h @@ -0,0 +1,163 @@ +#pragma once + +#include +//#include +#include +#include + +namespace Json { + + class Value; + +} +class ExplainTreeModelItem; +typedef std::shared_ptr 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 { +public: + typedef std::shared_ptr 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 m_childItems; + std::weak_ptr 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; + static SPtr createFromJson(Json::Value &json); + + ExplainTreeModelItemPtr plan; + float planningTime = 0.f; + // Triggers??? + float executionTime = 0.f; + float totalRuntime = 0.f; + +}; + diff --git a/core/core.pro b/core/core.pro index bb40f96..6b6663a 100644 --- a/core/core.pro +++ b/core/core.pro @@ -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 } + + diff --git a/pglab/json/json-forwards.h b/core/json/json-forwards.h similarity index 100% rename from pglab/json/json-forwards.h rename to core/json/json-forwards.h diff --git a/pglab/json/json.h b/core/json/json.h similarity index 100% rename from pglab/json/json.h rename to core/json/json.h diff --git a/pglab/jsoncpp.cpp b/core/jsoncpp.cpp similarity index 100% rename from pglab/jsoncpp.cpp rename to core/jsoncpp.cpp diff --git a/pglab/BaseTableModel.cpp b/pglab/BaseTableModel.cpp new file mode 100644 index 0000000..de5e077 --- /dev/null +++ b/pglab/BaseTableModel.cpp @@ -0,0 +1,36 @@ +#include "BaseTableModel.h" +#include "ResultTableModelUtil.h" +#include + +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; +} diff --git a/pglab/BaseTableModel.h b/pglab/BaseTableModel.h new file mode 100644 index 0000000..c6d6e8e --- /dev/null +++ b/pglab/BaseTableModel.h @@ -0,0 +1,21 @@ +#ifndef BASETABLEMODEL_H +#define BASETABLEMODEL_H + +#include +#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 diff --git a/pglab/DatabasesTableModel.cpp b/pglab/DatabasesTableModel.cpp index 0047af1..58d7eec 100644 --- a/pglab/DatabasesTableModel.cpp +++ b/pglab/DatabasesTableModel.cpp @@ -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; } diff --git a/pglab/DatabasesTableModel.h b/pglab/DatabasesTableModel.h index cc15528..a011d10 100644 --- a/pglab/DatabasesTableModel.h +++ b/pglab/DatabasesTableModel.h @@ -1,7 +1,7 @@ -#ifndef DATABASESTABLEMODEL_H +#ifndef DATABASESTABLEMODEL_H #define DATABASESTABLEMODEL_H -#include +#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; diff --git a/pglab/ExplainTreeModelItem.cpp b/pglab/ExplainTreeModelItem.cpp deleted file mode 100644 index f756b1f..0000000 --- a/pglab/ExplainTreeModelItem.cpp +++ /dev/null @@ -1,384 +0,0 @@ -#include "ExplainTreeModelItem.h" -#include "json/json.h" -#include - -namespace { - - ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan) - { - ExplainTreeModelItemPtr result = std::make_shared(); - 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(); - // 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::infinity(); - } - } - else if (m_actualRows > m_estimatedRows) { - if (m_estimatedRows > 0) { - res = float(m_actualRows) / m_estimatedRows; - } - else { - res = std::numeric_limits::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" -//} diff --git a/pglab/ExplainTreeModelItem.h b/pglab/ExplainTreeModelItem.h deleted file mode 100644 index 5c28599..0000000 --- a/pglab/ExplainTreeModelItem.h +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once - -#include -//#include -#include -#include - -namespace Json { - - class Value; - -} -class ExplainTreeModelItem; -typedef std::shared_ptr 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 { -public: - typedef std::shared_ptr 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 m_childItems; - std::weak_ptr 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; - static SPtr createFromJson(Json::Value &json); - - ExplainTreeModelItemPtr plan; - float planningTime = 0.f; - // Triggers??? - float executionTime = 0.f; - float totalRuntime = 0.f; - -}; - diff --git a/pglab/PgDatabaseCatalogue.cpp b/pglab/PgDatabaseCatalogue.cpp index ca53c0c..155218e 100644 --- a/pglab/PgDatabaseCatalogue.cpp +++ b/pglab/PgDatabaseCatalogue.cpp @@ -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() { } diff --git a/pglab/PgDatabaseCatalogue.h b/pglab/PgDatabaseCatalogue.h index 1911708..d8f7548 100644 --- a/pglab/PgDatabaseCatalogue.h +++ b/pglab/PgDatabaseCatalogue.h @@ -45,5 +45,7 @@ private: }; QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid); +QString getRoleDisplayString(const PgDatabaseCatalogue *cat, Oid oid); + #endif // PGSQLDATABASECATALOGUE_H diff --git a/pglab/PgDatabaseContainer.cpp b/pglab/PgDatabaseContainer.cpp index ba5b729..78e0adb 100644 --- a/pglab/PgDatabaseContainer.cpp +++ b/pglab/PgDatabaseContainer.cpp @@ -1,5 +1,6 @@ -#include "PgDatabaseContainer.h" +#include "PgDatabaseContainer.h" #include "Pgsql_Connection.h" +#include "Pgsql_Col.h" PgDatabaseContainer::PgDatabaseContainer(PgDatabaseCatalogue *cat) : PgContainer(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()); diff --git a/pglab/QueryExplainModel.cpp b/pglab/QueryExplainModel.cpp index 67ccfca..019ad7c 100644 --- a/pglab/QueryExplainModel.cpp +++ b/pglab/QueryExplainModel.cpp @@ -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) { diff --git a/pglab/QueryResultModel.cpp b/pglab/QueryResultModel.cpp index 9371ffd..c6449c5 100644 --- a/pglab/QueryResultModel.cpp +++ b/pglab/QueryResultModel.cpp @@ -1,4 +1,5 @@ #include "QueryResultModel.h" +#include "ResultTableModelUtil.h" #include "Pgsql_declare.h" #include #include @@ -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); } diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index c0ff2f2..7db03a9 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -1,4 +1,4 @@ -#include "QueryTab.h" +#include "QueryTab.h" #include "ui_QueryTab.h" #include "SqlSyntaxHighlighter.h" #include @@ -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> exp_res, qint64 ) { if (exp_res.valid()) { // Process explain data seperately auto res = exp_res.get(); - std::thread([this,res]() - { - std::shared_ptr 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 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(); + } } }); } diff --git a/pglab/ResultTableModelUtil.cpp b/pglab/ResultTableModelUtil.cpp new file mode 100644 index 0000000..e50e285 --- /dev/null +++ b/pglab/ResultTableModelUtil.cpp @@ -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"; +} + diff --git a/pglab/ResultTableModelUtil.h b/pglab/ResultTableModelUtil.h new file mode 100644 index 0000000..98543a6 --- /dev/null +++ b/pglab/ResultTableModelUtil.h @@ -0,0 +1,23 @@ +#pragma once +#include "Pgsql_declare.h" +#include +#include + +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); + diff --git a/pglab/RolesTableModel.cpp b/pglab/RolesTableModel.cpp index 9744494..d3acd19 100644 --- a/pglab/RolesTableModel.cpp +++ b/pglab/RolesTableModel.cpp @@ -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; } diff --git a/pglab/RolesTableModel.h b/pglab/RolesTableModel.h index 0da4375..77c8c85 100644 --- a/pglab/RolesTableModel.h +++ b/pglab/RolesTableModel.h @@ -2,14 +2,14 @@ #define ROLESTABLEMODEL_H -#include +#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; diff --git a/pglab/icons/about.png b/pglab/icons/about.png index 1a02d2bd7d2cc56b26440197f30eead86dc1c3c7..93c67f2bf0e6e07da700bc508b7b9f55e5c6f89a 100644 GIT binary patch delta 2100 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 RW7hxx002ovPDHLkV1h(i%^Ls! delta 390 zcmV;10eSw&3!np#BYy#BNkl`cyVCV0Yk|F1DpsM7$Dh@nwTWZVGbBA2S#!(7psXC2vt?aG=#rT2&I{cCBV(rpZh!Bc7P{3t%y$qV$^qo$ z_r~=-`7R4RKBHTXirvoRbp*Lluy6mB|K5uOQ7pUg;^O}c&oBO8du=_sL-ylw0C|b9 zVr?^qZ(-oVi;Ea?PV-$8sOEs<2k&7GZhQ`Kp6|YaY7SVt`v6L?;{!!IO5th;s{=?+ zgvbt9du=@=@qZyXzS{+4ONw@s{x8~53J-Qf7IbT%s^w^oIDoGtq?zT&z-hi~g7bX$ k4G2r!A2`o5I8Vw?dVR09th(n|*OZEgvBp{NoSb`9uL=nt3gcOpA$shqmW2sV5Tu_#x zhzdneq@q-%pv7WY6tHYs*{L94WeZXfu-st9-XGUH&olEa&pGEk@A6~feSJKPk*kmh z1j5+Mlfl-m!0c7ggpd@=pT%HRQn{9mKsdRmz^o!)07bxbwASfADM;m?WM#^aWzrT5r{c?T1T20wr8yvr_5Yz#=_j-jW`qCw z{hz{0PLv$Pu|Xvip%7{t7qV_Pl$_?K0QoSa;6PCLTorvoAsAAILUO>(pMoU-0TP)A zid25Uvsg4QnG)v9grFCLj@Bw*B@z+M-Q9ug=uTo%9Nnn|0+Z;<&{oQUOtL319SKwd zWsb{$gb`9u2G4Ot|8m_w%bgtssazYG0V*W>K#{uwk^&!6rb#~U#qG0tAGxB>dtrQ* zi_@CH%{KPG8a;QVou1k4r?J%@J`Fx7(@wiWJJ!}NS5G1kdiT5-t{hcMX+Yq%-P@N3 z_YuWB>~Y;1gmuww8}fSO%3a80POD&5mP8;}CM9oGX-w0aOdIScIWy|f2LWg9Pw>3I z&oO=dgG=Uj}Srr&Cyv^z`1)(9G25)X+cL}tVzTg ztMnQ=P*bcz3N&U3%%EzJA@F9+f8|8b@D1)#5r#(0w96G@#aX<*RRCXYKTCx&WywELKcK#NI?5E6+hzr$4vF zuHD7uW{15l?#7{6&%iz6;hKEC`8&%kM8GkUqv4uUN3;d0*s;Xd+3{U>!N$HNy-7Yl zyhQu%39!9%A?-XmcI*cdm7;&NK~;KQP)M{UadiGN%Cx-6y;jg+IdHfD4%rUt>T-h( zt5Ck?24@ee04%~UBn3oHjnYqhR$1gc%5LCTJEs)pov9X+#tN^HMt1}RF!K(37HfKn z=2<%2uwQlYSHWmqQWCyT6R&EF;<;oTnE9q>*;xN+hkl+%iOS^U0rSMbShuqR{Hdat z8D~rDsPSQ+?GcYqez7th;_;WUVs)K`$C`%UlUi3hEEsr__g!0e-T-Q6A8D=c+Hho-o=Po!C^S`L@5%Z_$xoAOR_3t0C}m zu(f=;bJQTyxV&m_xzM2}MBF#<_j{^W@=#-Fq}#puD%lXuCm!3rWWNLp@$fqw*19A^ z>Xh1$+J*-9F7EE-i|U;ac&F*OGf#}Wg5!3dV_cG}gL_j9vw%%R`yn%Rf}lW@wr!Ma zRGJWe9FbWcteJ{w8~47=-TV9+{ry+EV==TNv98_TAgCAl*v9e;&&a8|pbdJtW@PdS z16ViK_^QUS3w3eF!xvj>;Fjuh9ywQD+|tQkF_;?Lx0{xN89yYRz|s#)+*#aQvWSO= zb;}B^<*Q~b{{jbV!Z$byw7L%F|(5H98 zx9n~>4-H5k@EPj(>nW*~kDmWhq#QwY^zGVU`)cN0l5zt8hPuBChRjkJmaH6>-TE*{)_dpO#rczU3w zhHPx2xUNjJ)jN3NxyI@-J1oq$Gi}pATR@*oWnJc2-}1DgIPh|MMv0;ZldCh7wcZT5 z?1rkea%_`X*Nb=i@MeOilkb9Yk)8AOPN)Y20OGBv%? z@%!}A6r=WQ9zk#G2O7mzGbRfSUCc-9#>dBde~KCcH4~%41O~b_X(rJLv115zJERP` zXZeG+K=~A#xA5tD-KFthK|NZh(?|DwWvynVzEyzrVx#a$3a39aL`aet%@Lm7_ delta 446 zcmV;v0YU!B64wKeBYy#&Nkl?fR;1+J_CV`C4M6H@53~q?z9ApbHxj^K0)MQy2o=R`Lzyd5@-IL# z2mW&x$OAN*CN!GnY5>)`1?dunYTf$%Igr?+k0CV z&Vx#r3z%MA3>~2&J3$3VeG3q$-)|o6-ObBjfDd7>p$OSWa9p$DpfY|@2^|ZtRtP{| z5pD=Yh>8=02!DI?cY=sk2t~lrwH*NPKSo|LV%l3+h;e4XI&rv47_1S8o!{DrLH`4Y@SNWX zw7d`yClF@ZOs`{}nR!ll4q-a--YHIyTtER*Vu5)O!Z%uC;^}=&YVtXRAtno$gg=vf o27-AOVWxYDG3_Bj%k$g*398>mDziC1-T(jq07*qoM6N<$g47Yn1ONa4 diff --git a/pglab/icons/delete_connection.png b/pglab/icons/delete_connection.png index 556398415d250dd7238581fbf1ff5d93d9e90591..a6998641ca0601606180b7951fadc09a0ddf8ebd 100644 GIT binary patch delta 1480 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 delta 594 zcmV-Y0i*Wj0^G^o5ig*5UmOu!De+2hI6y*wW?vm#TzM*6^&)jK>WK0 z#OX?*HvoXogiFgCzKg?-_yv3uVu>t7^aRL?2IsEmUsc2Qo~;N0a3S>c6sU&H#8)fZ ztUeI84rE1xaNJ5H0n(-OOK)db{b?wgIFT#tA9P1dG=0LGzbljI_;;@5gyGVTeDyIh^GQ}T=o?D89T*X2!nM_1&?lzZY(v*>IbF!X+}sP8 zu;-Z>FOOwCCZr?~f@lBB<&8^T6GoF6IIqUOdAC4TG>D9hAKHQ=0C)qNlz1;!4I9F7 z144tN&`URz^1r+-{xQ&mrvf0QE^N{TY!-Sk$#-LmRu27y2dw6t6DIysAd^ZyfS{fK gZ2(5`%t_|`10He<#-|gzPXGV_07*qoM6N<$g1Ac?O8@`> diff --git a/pglab/icons/new_query_tab.png b/pglab/icons/new_query_tab.png index 40f546e9b282972c11c9faac976ff59832bf8463..d33fc2bd253bb5a67ffbe23a7562423a59dae3ff 100644 GIT binary patch delta 1253 zcmVp~|_o$Ad7A|n8&W;C~3MxMuGg4j@0w3L{b z6T}PvoC{i+edEl$3!J;)^?Km<`OM=eDK1`00`H#;sBfB*_0P_eWM*wIx;;|8|S-o1bOf8w(oH929(==e40h&89Hi|fz zAx2AlK`^kyWY-n|$sqt8#cTo2b|A``fw`Em17aos&P-wbA1&h%;4T4R({75*BjEFJ zsNW!A7Jv3#lG`Z*P92M&MEOBdAZyQb620=h&P3?cIhSO(Wd$AKX4JJG!1sT&X(VWe zNnlnjc@j@lU}Z-QZUE`!#!LW`vna^9438|Ms_7Mc({&s#tl5d9>#LBb__R5RiBWWg z+cB(mw*($ZeERJH?6s!pc`?8xm*)I~v!&?hJAa4w%a5Wz){YB32Qd&&1*U-ChsT0D z@Xm|X`1tF0U)y?UkTo4dr2#_9qyam|iCdW~=!~?WwdWk(+WsMa4j(~#q!z;z6_0IK zH5(cmL0hB-KlUC%<#YRyzsUb;$=fJ0R3c@%1*v>6w@I{nN`CmfZ69{7-G$D-kCU@L zQh$7UU=)2Zc5^g>-~ajy&p%ZTcL5F?*)jKeKvY7scym`P9taemFLni!B(Hyyzi$ z09?dyJ89Tbip9sn8qL{7o0`ikfim}7z<-Qf4-#Dz9@@`)%?uMnMS}hcs<)=L@n#c) zhrGz-JdftwPV}c~M4FybjY>D08H;RrbTbA9sU9Rrc`4%h$-I`*L-e&VcWTbfA%H@| zZ$?0pU@6C)2+?Sj&sO0|Pl^x<36NbWM`od_k14V^UZCe1(0>`#LZ4|zz*IGMx__~8 zfmS}*Dkek-=0xv8tjgbp)=THH;Tc*`NeT1tMP@P}00@;{yhO*3+3; z!+h#5C%Y%dT+E+-1Fzq|0;LZ>MA0umK=iFmk{+T_;Loc>e+1`$_z3%H_&Qlk9D@Ns z)~i+}$4o5pZ9(B?tY5YkdzFQF++Ms&w4L#P&>8*(pIp6wpJ+ss=(mkfYyg;V?ZNd8 z6p-CV=C}Ny3P*7=k}61o7_la!y9L0wn6e(>6l;O33r?K*#PoFhp8x{@EQF+u|NkFf P00000NkvXXu0mjf)!bA^ delta 394 zcmV;50d@ZP38Mp$BYy#ENklu}Z^G6b9fvLLb3L2?@RFT3^6SO4mSeY0;^m z8QR6k;YLNAN`fF{Y9bT@Ati}m=h~%32rd=cNIec}+B7B5-WvtY4`&I1^X25+TPWmN zlcqg2TlNgLEc|PL&hQP+dK3`b0(#GL@Pj!yf&}pN`c94@1%D7DXaI;1v;fP9rX992 z2Ph9ATt6o3+?_$wo|>5h(kch!fE@5Y0kRc9&2*q}o6e<|AMq|VW8%;E^NsSNs zV5_ONTCx5_jrw9tUrMxSphBp0p$O7iHEEhyDgm{&u{1PkZGWX@-QAhFo^yBhhuwu8 zU~h6~c4qH6=eyte&b@bploH&85OA8Y^^>o@)^+3I=zp^{wzDjA@79fvKT3}#=Fr%` zNCKe0_EBrw(i^V#mEKkiX-muofh~k4Ffw`qsKIzsr5rDAiV%xTQsI4e= z4dB4h6UxqxO9S%(z?{IMnd>C1oqK+OM)%pgNd;J9MSp3LvYQia=>Tv}A`D0sTvq_Z zEC6Ke7u(5&0^k{#(x$q$ad*j5*G_mm+hvCVGg1|6%S#-RGfEKtBcn09g#qB4(oA@9 zX=xi!HJ(ue6qMOwySax?!+>c;sO0=>Ldyt1IMlP zDg%~jD}P1T-BYR%W!ejP73%qAMA>Df3V1f0`*+)h=$>I&k*om_Th}PN>{J2gR75o( zG6E1%T_Pe}FaQc>5|u2dvZ4alPIx@qNfK=qQoy_d4J*sw_CT`lr{9#Fh!6KZ^ge=? ziLUOKG3)l6T86d>p2&OO9E1=vO3zuMg%auVWq*ZA3qpFLgYtLb0$5ay}7+M~I$wTLGGmf0@Q!|&x9cSci?G8*ZErB3sG6!|# z&3|Ov>H~r3+mgyess@}D&9Y7 zS`zq;}M)&GU1VaJT zR^5s~Xi`ys+4`HZjkH~Osq>wtD2cJrbGxykY&kzS(TLo%BIFc=O;Z8s=skqSHLKC# zA3~FJZ(Oqq?f%1f@cx_B6sP1k^c<+JC3kNmICIP_*q$JM{{0w2|6;&_Im2E+Jb&{Z z=&QRId-wl{N9wEbtv`PEty_(*{xLc+0YUu~a`KZ4G`>WeVJ8SN@E4JFpdW*SE!ae_ z!ZDkK?}BSLzW(XN`i2^WLgCoqGEBb-FR%uZkL5BjHF>c6yMMu|Oe-LL!%#VHz@6e*3aZDlIeG5l(B~gKvz>=D zyp4Sx%Jk?M&3r!ve?mQi1lQl2ii1nL*5pJ$OZ?!-t{HPF+6!GV_a z!IK#XID^j4^=$7n&RNj$Q%DOZ`nqs@{{U)BJde?j!z8%E^DD+1Bsh4Fu5T|ijOuJLuU59YV zOpdu^hI`{hj&Uc#z3~F>M6s1I9*EQUQ^zD>tIkl(+o+xNP$}5pP6VqHqMWs$YZT?I z1*;Q+7!#DU7JrB_N%98S8bH@5T6HGBX?F@;qiCGF5>VIZW&pdCVf&J!oVC!rc$Drw zD-yIXxty;QY;^zu6ClO}x<+LPRspJcg#fxnVRb?TOh^NJ4MD5UP$}4`m3pY=ZMbB% zl!VS&64pvR=$Zrb%HIwksSK@7h@0kUtqgCPBb*fpT5WX(?nEHQMC$U|jmq$gH@0X* z+=)QD)AWrf>@RXY6SqE_Kln@xckFuKHKF0>p0{Ctk^7NTr_gwB9R7Fwn*n~!mF!@b q(mjRXzz>s5=HqFmQWK5;NqGlD$2WZ~{qvLn0000 icons/server_delete.png - icons/server_go.png icons/script_delete.png icons/script_go.png icons/folder.png diff --git a/pglabAll.pro b/pglabAll.pro index 890c392..503beee 100644 --- a/pglabAll.pro +++ b/pglabAll.pro @@ -2,10 +2,11 @@ TEMPLATE = subdirs DEFINES += BOOST_ENABLE_ASSERT_HANDLER + SUBDIRS += core \ pgsql \ - pglab +pglab CONFIG(debug, debug|release) { -# SUBDIRS += tests +SUBDIRS += tests } diff --git a/pgsql/Pgsql_Col.cpp b/pgsql/Pgsql_Col.cpp new file mode 100644 index 0000000..47c64a1 --- /dev/null +++ b/pgsql/Pgsql_Col.cpp @@ -0,0 +1,2 @@ +#include "Pgsql_Col.h" + diff --git a/pgsql/Pgsql_Col.h b/pgsql/Pgsql_Col.h new file mode 100644 index 0000000..87e2ad7 --- /dev/null +++ b/pgsql/Pgsql_Col.h @@ -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 +// void operator<<(T &s, Col &c) +// { +// s << c.nextValue(); +// } + + template + Col& operator>>(Col &c, T &s) + { + s << c.nextValue(); + return c; + } + +} // end namespace Pgsql + +#endif // PGSQL_COL_H diff --git a/pgsql/Pgsql_Params.h b/pgsql/Pgsql_Params.h index a9e9950..950e86d 100644 --- a/pgsql/Pgsql_Params.h +++ b/pgsql/Pgsql_Params.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(); diff --git a/pgsql/Pgsql_Row.h b/pgsql/Pgsql_Row.h index f62df72..81d5ae0 100644 --- a/pgsql/Pgsql_Row.h +++ b/pgsql/Pgsql_Row.h @@ -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; diff --git a/pgsql/Pgsql_Value.cpp b/pgsql/Pgsql_Value.cpp index e4095cb..26aaeb7 100644 --- a/pgsql/Pgsql_Value.cpp +++ b/pgsql/Pgsql_Value.cpp @@ -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) diff --git a/pgsql/Pgsql_Value.h b/pgsql/Pgsql_Value.h index 8b07046..ae06160 100644 --- a/pgsql/Pgsql_Value.h +++ b/pgsql/Pgsql_Value.h @@ -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; diff --git a/pgsql/Pgsql_declare.h b/pgsql/Pgsql_declare.h index 279d09b..f54c6a8 100644 --- a/pgsql/Pgsql_declare.h +++ b/pgsql/Pgsql_declare.h @@ -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; diff --git a/pgsql/pgsql.pro b/pgsql/pgsql.pro index 9115bd2..ea9f394 100644 --- a/pgsql/pgsql.pro +++ b/pgsql/pgsql.pro @@ -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 += diff --git a/tests/PgsqlTests/.gitignore b/tests/PgsqlTests/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/tests/PgsqlTests/.gitignore @@ -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 + diff --git a/tests/PgsqlTests/PgsqlTests.pro b/tests/PgsqlTests/PgsqlTests.pro new file mode 100644 index 0000000..017b97f --- /dev/null +++ b/tests/PgsqlTests/PgsqlTests.pro @@ -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 diff --git a/tests/PgsqlTests/gtest_dependency.pri b/tests/PgsqlTests/gtest_dependency.pri new file mode 100644 index 0000000..d01d7f0 --- /dev/null +++ b/tests/PgsqlTests/gtest_dependency.pri @@ -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 diff --git a/tests/PgsqlTests/main.cpp b/tests/PgsqlTests/main.cpp new file mode 100644 index 0000000..291bdee --- /dev/null +++ b/tests/PgsqlTests/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/PgsqlTests/tst_Value.cpp b/tests/PgsqlTests/tst_Value.cpp new file mode 100644 index 0000000..092b9f1 --- /dev/null +++ b/tests/PgsqlTests/tst_Value.cpp @@ -0,0 +1,66 @@ +#include +#include +#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); +} diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro new file mode 100644 index 0000000..576a9ff --- /dev/null +++ b/tests/auto/auto.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += mycase diff --git a/tests/auto/gtest_dependency.pri b/tests/auto/gtest_dependency.pri new file mode 100644 index 0000000..d01d7f0 --- /dev/null +++ b/tests/auto/gtest_dependency.pri @@ -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 diff --git a/tests/auto/mycase/main.cpp b/tests/auto/mycase/main.cpp new file mode 100644 index 0000000..046652f --- /dev/null +++ b/tests/auto/mycase/main.cpp @@ -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 + +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/auto/mycase/mycase.pro b/tests/auto/mycase/mycase.pro new file mode 100644 index 0000000..bb3a635 --- /dev/null +++ b/tests/auto/mycase/mycase.pro @@ -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 diff --git a/tests/auto/mycase/tst_CsvWriter.h b/tests/auto/mycase/tst_CsvWriter.h new file mode 100644 index 0000000..ac48b9d --- /dev/null +++ b/tests/auto/mycase/tst_CsvWriter.h @@ -0,0 +1,113 @@ +#include +#include +#include "CsvWriter.h" +#include +#include + +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)); +} diff --git a/tests/auto/mycase/tst_ExplainJsonParser.cpp b/tests/auto/mycase/tst_ExplainJsonParser.cpp new file mode 100644 index 0000000..e5074eb --- /dev/null +++ b/tests/auto/mycase/tst_ExplainJsonParser.cpp @@ -0,0 +1,80 @@ +#include +#include +#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); +} diff --git a/tests/auto/mycase/tst_PasswordManager.h b/tests/auto/mycase/tst_PasswordManager.h new file mode 100644 index 0000000..a3da28b --- /dev/null +++ b/tests/auto/mycase/tst_PasswordManager.h @@ -0,0 +1,73 @@ +#include +#include +#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) ); + +} diff --git a/tests/auto/mycase/tst_SqlLexer.h b/tests/auto/mycase/tst_SqlLexer.h new file mode 100644 index 0000000..25d6535 --- /dev/null +++ b/tests/auto/mycase/tst_SqlLexer.h @@ -0,0 +1,38 @@ +#include +#include +#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)); +} + diff --git a/tests/auto/mycase/tst_expected.h b/tests/auto/mycase/tst_expected.h new file mode 100644 index 0000000..8632ff8 --- /dev/null +++ b/tests/auto/mycase/tst_expected.h @@ -0,0 +1,203 @@ +#include +#include +#include "Expected.h" + +using namespace testing; + +Expected getAnswerToEverything() { return 42; } + +TEST(expected, valid_when_valid_returns_true) +{ + Expected v = getAnswerToEverything(); + ASSERT_THAT(v.valid(), Eq(true)); +} + +TEST(expected, get_when_valid_returns_value) +{ + Expected v = getAnswerToEverything(); + ASSERT_THAT(v.get(), Eq(42)); +} + +TEST(expected, hasException_when_valid_returns_false) +{ + Expected v = getAnswerToEverything(); + ASSERT_THAT(v.hasException(), Eq(false)); +} + +TEST(expected, T_fromException_is_not_valid) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.valid(), Eq(false)); +} + +TEST(expected, T_fromException_get_thows) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THROW (e.get(), std::runtime_error); +} + +TEST(expected, T_fromException_has_exception_true) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +TEST(expected, T_fromException_has_exception_false) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.hasException(), Eq(false)); +} + +TEST(expected, T_fromException_has_derived_exception) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +TEST(expected, T_fromCode_is_valid) +{ + auto e = Expected::fromCode([]() -> int { return 42; }); + ASSERT_THAT(e.valid(), Eq(true)); +} + +TEST(expected, T_fromCode_get) +{ + auto e = Expected::fromCode([]() -> int { return 42; }); + ASSERT_THAT(e.get(), Eq(42)); +} + + +TEST(expected, T_fromCode_E_is_not_valid) +{ + auto e = Expected::fromCode([]() -> int { throw std::runtime_error("hello"); }); + ASSERT_THAT(e.valid(), Eq(false)); +} + +TEST(expected, T_fromCode_E_get_thows) +{ + auto e = Expected::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::fromCode([]() -> int { throw std::runtime_error("hello"); }); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +TEST(expected, T_fromCode_E_has_exception_false) +{ + auto e = Expected::fromCode([]() -> int { throw std::runtime_error("hello"); }); + ASSERT_THAT(e.hasException(), Eq(false)); +} + +TEST(expected, T_fromCode_E_has_derived_exception) +{ + auto e = Expected::fromCode([]() -> int { throw std::runtime_error("hello"); }); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +//Expected getIntWithStdRuntimeError() { return Expected(); } + +Expected getNothing() { return Expected(); } + + +TEST(expected_void, valid_when_valid_returns_true) +{ + Expected v = getNothing(); + ASSERT_THAT(v.valid(), Eq(true)); +} + +TEST(expected_void, get_when_valid_returns_value) +{ + Expected v = getNothing(); + ASSERT_NO_THROW(v.get()); +} + +TEST(expected_void, hasException_when_valid_returns_false) +{ + Expected v = getNothing(); + ASSERT_THAT(v.hasException(), Eq(false)); +} + + + + + + +TEST(expected_void, void_fromException_is_not_valid) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.valid(), Eq(false)); +} + +TEST(expected_void, void_fromException_get_thows) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THROW (e.get(), std::runtime_error); +} + +TEST(expected_void, void_fromException_has_exception_true) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +TEST(expected_void, void_fromException_has_exception_false) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.hasException(), Eq(false)); +} + +TEST(expected_void, void_fromException_has_derived_exception) +{ + auto e = Expected::fromException(std::runtime_error("hello")); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +TEST(expected_void, void_fromCode_is_valid) +{ + auto e = Expected::fromCode([]() -> void { }); + ASSERT_THAT(e.valid(), Eq(true)); +} + +TEST(expected_void, void_fromCode_get) +{ + auto e = Expected::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::fromCode(expected_void_throws_func); + ASSERT_THAT(e.valid(), Eq(false)); +} + +TEST(expected_void, void_fromCode_E_get_thows) +{ + auto e = Expected::fromCode(expected_void_throws_func); + ASSERT_THROW (e.get(), std::runtime_error); +} + +TEST(expected_void, void_fromCode_E_has_exception_true) +{ + auto e = Expected::fromCode(expected_void_throws_func); + ASSERT_THAT(e.hasException(), Eq(true)); +} + +TEST(expected_void, void_fromCode_E_has_exception_false) +{ + auto e = Expected::fromCode(expected_void_throws_func); + ASSERT_THAT(e.hasException(), Eq(false)); +} + +TEST(expected_void, void_fromCode_E_has_derived_exception) +{ + auto e = Expected::fromCode(expected_void_throws_func); + ASSERT_THAT(e.hasException(), Eq(true)); +} diff --git a/tests/auto/mycase/tst_scopeguard.h b/tests/auto/mycase/tst_scopeguard.h new file mode 100644 index 0000000..2b14280 --- /dev/null +++ b/tests/auto/mycase/tst_scopeguard.h @@ -0,0 +1,63 @@ +#include +#include +#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 v = getAnswerToEverything(); +// ASSERT_THAT(v.get(), Eq(42)); +//} + diff --git a/tests/mygtestutils/PrintTo_Qt.cpp b/tests/mygtestutils/PrintTo_Qt.cpp new file mode 100644 index 0000000..fdfc571 --- /dev/null +++ b/tests/mygtestutils/PrintTo_Qt.cpp @@ -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(); +} diff --git a/tests/mygtestutils/PrintTo_Qt.h b/tests/mygtestutils/PrintTo_Qt.h new file mode 100644 index 0000000..16a8d8b --- /dev/null +++ b/tests/mygtestutils/PrintTo_Qt.h @@ -0,0 +1,11 @@ +#ifndef PRINTTO_QT_H +#define PRINTTO_QT_H + +#include +#include +#include + +void PrintTo(const QDateTime &dt, ::std::ostream* os); +void PrintTo(const QString &s, ::std::ostream* os); + +#endif // PRINTTO_QT_H diff --git a/tests/mygtestutils/mygtestutils.pro b/tests/mygtestutils/mygtestutils.pro new file mode 100644 index 0000000..a56a359 --- /dev/null +++ b/tests/mygtestutils/mygtestutils.pro @@ -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 +} diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..b3fc93a --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += auto \ + PgsqlTests \ + mygtestutils