diff --git a/core/PasswordManager.cpp b/core/PasswordManager.cpp index 0a52265..5f67395 100644 --- a/core/PasswordManager.cpp +++ b/core/PasswordManager.cpp @@ -61,14 +61,14 @@ public: return base64_encode(wrapped_key); } - secure_vector get(const std::string& name, const std::string &wrapped_key) const + secure_vector get(const std::string& name, const std::string_view &wrapped_key) const { const std::vector wrapped_name = nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher); - const secure_vector val = base64_decode(wrapped_key); + const secure_vector val = base64_decode(wrapped_key.data(), wrapped_key.size()); std::unique_ptr wrap_cipher(m_cipher->clone()); wrap_cipher->set_key(m_hmac->process(wrapped_name)); @@ -169,7 +169,7 @@ std::string PasswordManager::encrypt(const std::string &name, const std::string } } -std::string PasswordManager::decrypt(const std::string &id, const std::string &encpwd) +std::string PasswordManager::decrypt(const std::string &id, const std::string_view &encpwd) { if (m_cryptoEngine) { secure_vector decoded = m_cryptoEngine->get(id, encpwd); diff --git a/core/PasswordManager.h b/core/PasswordManager.h index 291ef7e..c20f95d 100644 --- a/core/PasswordManager.h +++ b/core/PasswordManager.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,7 @@ public: bool locked() const; std::string encrypt(const std::string &id, const std::string &passwd); - std::string decrypt(const std::string &id, const std::string &encpwd); + std::string decrypt(const std::string &id, const std::string_view &encpwd); // void remove(const std::string &id); private: QString m_passwordTableName = "psk_passwd"; diff --git a/pglab/ConnectionConfigurationWidget.cpp b/pglab/ConnectionConfigurationWidget.cpp index 6bf5d18..a5837d0 100644 --- a/pglab/ConnectionConfigurationWidget.cpp +++ b/pglab/ConnectionConfigurationWidget.cpp @@ -169,16 +169,16 @@ void ConnectionConfigurationWidget::setData(const ConnectionConfig &cfg) } m_uuid = cfg.uuid(); - edtName->setText(stdStrToQ(cfg.name())); - edtHost->setText(stdStrToQ(cfg.host())); + edtName->setText(cfg.name()); + edtHost->setText(cfg.host()); spinPort->setValue(cfg.port()); - edtUser->setText(stdStrToQ(cfg.user())); - edtDbname->setText(stdStrToQ(cfg.dbname())); + edtUser->setText(cfg.user()); + edtDbname->setText(cfg.dbname()); cmbbxSsl->setCurrentIndex(static_cast(cfg.sslMode())); - edtCert->setText(stdStrToQ(cfg.sslCert())); - edtKey->setText(stdStrToQ(cfg.sslKey())); - edtRootCert->setText(stdStrToQ(cfg.sslRootCert())); - edtCrl->setText(stdStrToQ(cfg.sslCrl())); + edtCert->setText(cfg.sslCert()); + edtKey->setText(cfg.sslKey()); + edtRootCert->setText(cfg.sslRootCert()); + edtCrl->setText(cfg.sslCrl()); } std::tuple ConnectionConfigurationWidget::data() const @@ -188,16 +188,16 @@ std::tuple ConnectionConfigurationWidget::data() cons ConnectionConfig cfg; cfg.setUuid(m_uuid); - cfg.setName(qStrToStd(edtName->text())); - cfg.setHost(qStrToStd(edtHost->text())); + cfg.setName(edtName->text()); + cfg.setHost(edtHost->text()); cfg.setPort(static_cast(spinPort->value())); - cfg.setUser(qStrToStd(edtUser->text())); - cfg.setDbname(qStrToStd(edtDbname->text())); + cfg.setUser(edtUser->text()); + cfg.setDbname(edtDbname->text()); cfg.setSslMode(static_cast(cmbbxSsl->currentIndex())); - cfg.setSslCert(qStrToStd(edtCert->text())); - cfg.setSslKey(qStrToStd(edtKey->text())); - cfg.setSslRootCert(qStrToStd(edtRootCert->text())); - cfg.setSslCrl(qStrToStd(edtCrl->text())); + cfg.setSslCert(edtCert->text()); + cfg.setSslKey(edtKey->text()); + cfg.setSslRootCert(edtRootCert->text()); + cfg.setSslCrl(edtCrl->text()); return { group, cfg }; } diff --git a/pglab/ConnectionController.cpp b/pglab/ConnectionController.cpp index 78f5027..388c00b 100644 --- a/pglab/ConnectionController.cpp +++ b/pglab/ConnectionController.cpp @@ -12,7 +12,6 @@ #include #include - ConnectionController::ConnectionController(MasterController *parent) : QObject(parent) , m_masterController(parent) @@ -146,11 +145,12 @@ void ConnectionController::openServerWindowForConnection(QModelIndex index) bool ConnectionController::retrieveConnectionPassword(ConnectionConfig &cc) { auto enc_pwd = cc.encodedPassword(); - if (!enc_pwd.empty()) { + if (!enc_pwd.isEmpty()) { std::string pw; - bool result = decodePassword(getPskId(cc), cc.encodedPassword(), pw);// getPasswordFromPskdb(getPskId(cc), pw); + bool result = decodePassword(getPskId(cc), + std::string_view(enc_pwd.data(), enc_pwd.size()) , pw);// getPasswordFromPskdb(getPskId(cc), pw); if (result) { - cc.setPassword(pw); + cc.setPassword(QString::fromUtf8(pw.data(), pw.size())); return true; } } @@ -163,12 +163,14 @@ bool ConnectionController::retrieveConnectionPassword(ConnectionConfig &cc) int exec_result = dlg->exec(); if (exec_result == QDialog::Accepted) { - std::string password = dlg->password().toUtf8().data(); + auto password = dlg->password(); cc.setPassword(password); if (dlg->saveChecked()) { + auto ba = password.toUtf8(); + std::string pw(ba.data(), static_cast(ba.size())); std::string encoded_pw; - if (encodePassword(getPskId(cc), password, encoded_pw)) { - cc.setEncodedPassword(encoded_pw); + if (encodePassword(getPskId(cc), pw, encoded_pw)) { + cc.setEncodedPassword({ encoded_pw.data(), static_cast(encoded_pw.size()) }); } } return true; @@ -176,7 +178,7 @@ bool ConnectionController::retrieveConnectionPassword(ConnectionConfig &cc) return false; } -bool ConnectionController::decodePassword(const std::string &password_id, const std::string &enc_password, std::string &password) +bool ConnectionController::decodePassword(const std::string &password_id, const std::string_view &enc_password, std::string &password) { if (!UnlockPasswordManagerIfNeeded()) return false; diff --git a/pglab/ConnectionController.h b/pglab/ConnectionController.h index 4ef8491..9e1def3 100644 --- a/pglab/ConnectionController.h +++ b/pglab/ConnectionController.h @@ -2,6 +2,7 @@ #define CONNECTIONCONTROLLER_H #include +#include class MasterController; class ConnectionConfig; @@ -56,7 +57,7 @@ private: */ bool retrieveConnectionPassword(ConnectionConfig &cc); - bool decodePassword(const std::string &password_id, const std::string &enc_password, std::string &password); + bool decodePassword(const std::string &password_id, const std::string_view &enc_password, std::string &password); bool encodePassword(const std::string &password_id, const std::string &password, std::string &enc_password); /// diff --git a/pglab/ConnectionListModel.cpp b/pglab/ConnectionListModel.cpp index 8864165..4cac885 100644 --- a/pglab/ConnectionListModel.cpp +++ b/pglab/ConnectionListModel.cpp @@ -4,11 +4,13 @@ #include #include +#include #include #include #include #include #include +#include namespace { @@ -24,19 +26,19 @@ CREATE TABLE IF NOT EXISTS conngroup ( R"__( CREATE TABLE IF NOT EXISTS connection ( uuid TEXT PRIMARY KEY, - cname TEXT NOT NULL, + cname TEXT, conngroup_id INTEGER NOT NULL, - host TEXT NOT NULL, - hostaddr TEXT NOT NULL, + host TEXT , + hostaddr TEXT , port INTEGER NOT NULL, - user TEXT NOT NULL, - dbname TEXT NOT NULL, + user TEXT , + dbname TEXT , sslmode INTEGER NOT NULL, - sslcert TEXT NOT NULL, - sslkey TEXT NOT NULL, - sslrootcert TEXT NOT NULL, - sslcrl TEXT NOT NULL, - password TEXT NOT NULL + sslcert TEXT , + sslkey TEXT , + sslrootcert TEXT , + sslcrl TEXT , + password TEXT );)__"; @@ -68,22 +70,23 @@ R"__(INSERT OR REPLACE INTO connection QSqlQuery q(db); q.prepare(q_insert_or_replace_into_connection); q.bindValue(":uuid", cc.uuid().toString()); - q.bindValue(":name", stdStrToQ(cc.name())); + q.bindValue(":name", cc.name()); q.bindValue(":conngroup_id", conngroup_id); - q.bindValue(":host", stdStrToQ(cc.host())); - q.bindValue(":hostaddr", stdStrToQ(cc.hostAddr())); - q.bindValue(":port", cc.port()); - q.bindValue(":user", stdStrToQ(cc.user())); - q.bindValue(":dbname", stdStrToQ(cc.dbname())); + q.bindValue(":host", cc.host()); + q.bindValue(":hostaddr", cc.hostAddr()); + q.bindValue(":port", (int)cc.port()); + q.bindValue(":user", cc.user()); + q.bindValue(":dbname", cc.dbname()); q.bindValue(":sslmode", static_cast(cc.sslMode())); - q.bindValue(":sslcert", stdStrToQ(cc.sslCert())); - q.bindValue(":sslkey", stdStrToQ(cc.sslKey())); - q.bindValue(":sslrootcert", stdStrToQ(cc.sslRootCert())); - q.bindValue(":sslcrl", stdStrToQ(cc.sslCrl())); - q.bindValue(":password", stdStrToQ(cc.encodedPassword())); + q.bindValue(":sslcert", cc.sslCert()); + q.bindValue(":sslkey", cc.sslKey()); + q.bindValue(":sslrootcert", cc.sslRootCert()); + q.bindValue(":sslcrl", cc.sslCrl()); + q.bindValue(":password", cc.encodedPassword()); if (!q.exec()) { - return q.lastError(); + auto sql_error = q.lastError(); + return { sql_error }; } return {}; } @@ -129,18 +132,18 @@ void ConnectionTreeModel::load() while (q.next()) { auto cc = std::make_shared(); cc->setUuid(q.value(0).toUuid()); - cc->setName(qvarToStdStr(q.value(1))); - cc->setHost(qvarToStdStr(q.value(3))); - cc->setHostAddr(qvarToStdStr(q.value(4))); + cc->setName(q.value(1).toString()); + cc->setHost(q.value(3).toString()); + cc->setHostAddr(q.value(4).toString()); cc->setPort(static_cast(q.value(5).toInt())); - cc->setUser(qvarToStdStr(q.value(6))); - cc->setDbname(qvarToStdStr(q.value(7))); + cc->setUser(q.value(6).toString()); + cc->setDbname(q.value(7).toString()); cc->setSslMode(static_cast(q.value(8).toInt())); - cc->setSslCert(qvarToStdStr(q.value(9))); - cc->setSslKey(qvarToStdStr(q.value(10))); - cc->setSslRootCert(qvarToStdStr(q.value(11))); - cc->setSslCrl(qvarToStdStr(q.value(12))); - cc->setEncodedPassword(qvarToStdStr(q.value(13))); + cc->setSslCert(q.value(9).toString()); + cc->setSslKey(q.value(10).toString()); + cc->setSslRootCert(q.value(11).toString()); + cc->setSslCrl(q.value(12).toString()); + cc->setEncodedPassword(q.value(13).toByteArray()); int group_id = q.value(2).toInt(); auto find_res = std::find_if(m_groups.begin(), m_groups.end(), @@ -173,11 +176,11 @@ QVariant ConnectionTreeModel::data(const QModelIndex &index, int role) const // This is a connection if (role == Qt::DisplayRole) { switch (index.column()) { - case Name: v = stdStrToQ(conn->name()); break; - case Host: v = stdStrToQ(conn->host()); break; + case Name: v = conn->name(); break; + case Host: v = conn->host(); break; case Port: v = conn->port(); break; - case User: v = stdStrToQ(conn->user()); break; - case DbName: v= stdStrToQ(conn->dbname()); break; + case User: v = conn->user(); break; + case DbName: v= conn->dbname(); break; } } } @@ -338,7 +341,11 @@ void ConnectionTreeModel::save(const QString &group_name, const ConnectionConfig new_grp->add(node); auto save_res = saveToDb(*node); if (save_res) { - throw std::runtime_error("SqlError2"); + QString msg = save_res->text() + % "\n" % save_res->driverText() + % "\n" % save_res->databaseText(); + + throw std::runtime_error(msg.toUtf8().data()); } } @@ -446,3 +453,68 @@ std::optional ConnectionTreeModel::saveToDb(const ConnectionConfig &c { return SaveConnectionConfig(m_db, cc, cc.parent()->conngroup_id); } + + +Qt::DropActions ConnectionTreeModel::supportedDropActions() const +{ + return Qt::MoveAction; +} + +Qt::DropActions ConnectionTreeModel::supportedDragActions() const +{ + return Qt::MoveAction; +} + +Qt::ItemFlags ConnectionTreeModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); + + ConnectionConfig* cfg = getConfigFromModelIndex(index); + + if (cfg) + return Qt::ItemIsDragEnabled | defaultFlags; + else + return Qt::ItemIsDropEnabled | defaultFlags; +} + +//bool ConnectionTreeModel::insertRows(int row, int count, const QModelIndex &parent) +//{ +// return false; +//} + +//bool ConnectionTreeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) +//{ +// return false; +//} +namespace { + const auto mimeType = "application/vnd.pgLab.connection"; +} + +QStringList ConnectionTreeModel::mimeTypes() const +{ + return { mimeType }; +} + +QMimeData *ConnectionTreeModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *mimeData = new QMimeData; + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + for (const QModelIndex &index : indexes) { + if (index.isValid()) { + QString text = data(index, Qt::DisplayRole).toString(); + stream << text; + } + } + + mimeData->setData(mimeType, encodedData); + return mimeData; +} + +bool ConnectionTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + + return false; +} diff --git a/pglab/ConnectionListModel.h b/pglab/ConnectionListModel.h index 8a21db8..fae909b 100644 --- a/pglab/ConnectionListModel.h +++ b/pglab/ConnectionListModel.h @@ -80,6 +80,17 @@ private: int findGroup(const QString &name) const; std::optional saveToDb(const ConnectionConfig &cc); + + // QAbstractItemModel interface +public: + virtual Qt::DropActions supportedDropActions() const override; + virtual Qt::DropActions supportedDragActions() const override; + virtual Qt::ItemFlags flags(const QModelIndex &index) const override; +// virtual bool insertRows(int row, int count, const QModelIndex &parent) override; +// virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override; + virtual QStringList mimeTypes() const override; + virtual QMimeData *mimeData(const QModelIndexList &indexes) const override; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; }; #endif // CONNECTIONLISTMODEL_H diff --git a/pglab/ConnectionManagerWindow.cpp b/pglab/ConnectionManagerWindow.cpp index 20ffd5b..e40ea6b 100644 --- a/pglab/ConnectionManagerWindow.cpp +++ b/pglab/ConnectionManagerWindow.cpp @@ -18,6 +18,8 @@ ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidg { ui->setupUi(this); ui->treeView->setModel(m_connectionController->getConnectionTreeModel()); + ui->treeView->setDragDropMode(QAbstractItemView::InternalMove); + connect(ui->treeView, &QTreeView::activated, this, &ConnectionManagerWindow::connectionActivated); } diff --git a/pglab/CrudModel.cpp b/pglab/CrudModel.cpp index 3acc331..7646a71 100644 --- a/pglab/CrudModel.cpp +++ b/pglab/CrudModel.cpp @@ -434,7 +434,7 @@ std::tuple CrudModel::updateRow(const PendingRow & int row_number = pending_row.row(); Pgsql::Connection db_update_conn; auto dbconfig = m_database->config(); - db_update_conn.connect(dbconfig.getKeywords(), dbconfig.getValues(), false); + db_update_conn.connect(dbconfig.connectionString().toStdString().c_str()); auto result = db_update_conn.queryParam(buffer, params); if (result && result.rows() == 1) { @@ -523,7 +523,7 @@ std::tuple CrudModel::removeRows(const std::set try { Pgsql::Connection db_update_conn; auto dbconfig = m_database->config(); - db_update_conn.connect(dbconfig.getKeywords(), dbconfig.getValues(), false); + db_update_conn.connect(dbconfig.connectionString().toStdString().c_str()); // First delete rows in table QString delete_statement = createDeleteStatement(); diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 4467836..c8e86b7 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -94,7 +94,7 @@ void DatabaseWindow::setConfig(const ConnectionConfig &config) m_config = config; try { QString title = "pglab - "; - title += m_config.name().c_str(); + title += m_config.name(); setWindowTitle(title); auto f = TaskExecutor::run(new LoadCatalog(m_config)); diff --git a/pglab/OpenDatabase.cpp b/pglab/OpenDatabase.cpp index e5fd86f..dc4fd6c 100644 --- a/pglab/OpenDatabase.cpp +++ b/pglab/OpenDatabase.cpp @@ -3,6 +3,7 @@ #include "Pgsql_Connection.h" #include "Pgsql_PgException.h" #include "model/TypeSelectionItemModel.h" +#include OpenDatabase::OpenDatabaseSPtr OpenDatabase::createOpenDatabase(const ConnectionConfig &cfg) { @@ -27,10 +28,13 @@ OpenDatabase::~OpenDatabase() = default; void OpenDatabase::Init() { Pgsql::Connection conn; - auto kw = m_config.getKeywords(); - auto vals = m_config.getValues(); - conn.connect(kw, vals, 0); - m_catalog->loadAll(conn, nullptr); + std::string connstr = m_config.connectionString().toStdString(); + if (conn.connect(connstr.c_str())) { + m_catalog->loadAll(conn, nullptr); + } + else { + qDebug() << "Connect failed connstr: " << connstr.c_str(); + } } std::shared_ptr OpenDatabase::catalog() diff --git a/pglab/ServerWindow.cpp b/pglab/ServerWindow.cpp index 52267da..10eb0c6 100644 --- a/pglab/ServerWindow.cpp +++ b/pglab/ServerWindow.cpp @@ -40,6 +40,6 @@ void ServerWindow::setConfig(const ConnectionConfig &config) qWarning() << ex.text(); } QString title = "pglab - "; - title += m_config.name().c_str(); + title += m_config.name(); setWindowTitle(title); } diff --git a/pglabAll.pro.user.4.10-pre1 b/pglabAll.pro.user.4.10-pre1 new file mode 100644 index 0000000..319c1af --- /dev/null +++ b/pglabAll.pro.user.4.10-pre1 @@ -0,0 +1,481 @@ + + + + + + EnvironmentId + {78888978-f53a-469c-ac73-a847c4fa88dd} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 2 + true + true + 0 + 8 + true + 0 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + -fno-delayed-template-parsing + + true + + false + Builtin.TidyAndClazy + + + X:/Prog/pglab/pglab/ConnectionManagerWindow.cpp + X:/Prog/pglab/pglab/ConnectionConfigurationWidget.cpp + X:/Prog/pglab/pglab/ConnectionController.cpp + X:/Prog/pglab/pglab/ConnectionListModel.cpp + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.13.0 MSVC2017 32bit + Desktop Qt 5.13.0 MSVC2017 32bit + qt.qt5.5130.win32_msvc2017_kit + 0 + 0 + 0 + + X:/Prog/build-pglabAll-Desktop_Qt_5_13_0_MSVC2017_32bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + X:/Prog/build-pglabAll-Desktop_Qt_5_13_0_MSVC2017_32bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + true + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + X:/Prog/build-pglabAll-Desktop_Qt_5_13_0_MSVC2017_32bit-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + true + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + pglab + + Qt4ProjectManager.Qt4RunConfiguration:X:/Prog/pglab/pglab/pglab.pro + + 3768 + false + true + true + false + false + true + + X:/Prog/build-pglabAll-Desktop_Qt_5_13_0_MSVC2017_32bit-Debug/pglab + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + pglabtests + + Qt4ProjectManager.Qt4RunConfiguration:X:/Prog/pglab/tests/pglabtests/pglabtests.pro + + 3768 + false + true + true + false + false + true + + X:/Prog/build-pglabAll-Desktop_Qt_5_13_0_MSVC2017_32bit-Debug/tests/pglabtests + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + PgsqlTests + + Qt4ProjectManager.Qt4RunConfiguration:X:/Prog/pglab/tests/PgsqlTests/PgsqlTests.pro + + 3768 + false + true + true + false + false + true + + X:/Prog/build-pglabAll-Desktop_Qt_5_13_0_MSVC2017_32bit-Debug/tests/PgsqlTests + + 3 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 21 + + + Version + 21 + + diff --git a/pglablib/ASyncDBConnection.cpp b/pglablib/ASyncDBConnection.cpp index 90e44db..a33d53f 100644 --- a/pglablib/ASyncDBConnection.cpp +++ b/pglablib/ASyncDBConnection.cpp @@ -1,5 +1,6 @@ #include "ASyncDBConnection.h" #include "ScopeGuard.h" +#include "util.h" #include using namespace boost::asio; @@ -32,23 +33,23 @@ ASyncDBConnection::State ASyncDBConnection::state() const void ASyncDBConnection::setupConnection(const ConnectionConfig &config) { - m_config = config; - auto keywords = m_config.getKeywords(); - auto values = m_config.getValues(); - - bool ok = m_connection.connectStart(keywords, values); + m_config = config; +// auto keywords = m_config.getKeywords(); +// auto values = m_config.getValues(); + QString conn_string = config.connectionString(); + bool ok = m_connection.connectStart(conn_string.toStdString().c_str()); // auto start = std::chrono::steady_clock::now(); - if (ok && m_connection.status() != CONNECTION_BAD) { - auto sock_handle = m_connection.socket(); + if (ok && m_connection.status() != CONNECTION_BAD) { + auto sock_handle = m_connection.socket(); - m_asioSock.assign(ip::tcp::v4(), sock_handle); - m_asioSock.non_blocking(true); + m_asioSock.assign(ip::tcp::v4(), sock_handle); + m_asioSock.non_blocking(true); - m_asioSock.async_write_some(null_buffers(), - [this] (boost::system::error_code ec, std::size_t s) - { async_connect_handler(ec, s); } - ); - } + m_asioSock.async_write_some(null_buffers(), + [this] (boost::system::error_code ec, std::size_t s) + { async_connect_handler(ec, s); } + ); + } } void ASyncDBConnection::async_connect_handler(boost::system::error_code ec, std::size_t /*s*/) diff --git a/pglablib/ConnectionConfig.cpp b/pglablib/ConnectionConfig.cpp index e2fcfd6..f19edee 100644 --- a/pglablib/ConnectionConfig.cpp +++ b/pglablib/ConnectionConfig.cpp @@ -2,9 +2,19 @@ #include "util.h" #include #include +#include +#include namespace { + class registerMetaTypes { + public: + registerMetaTypes() + { + qRegisterMetaTypeStreamOperators("ConnectionConfig"); + } + } registerMetaTypes_instance; + struct { SslMode mode; const char* string; @@ -24,18 +34,17 @@ namespace { } // end unnamed namespace -std::string SslModeToString(SslMode sm) -{ - std::string result; +QString SslModeToString(SslMode sm) +{ for (auto e : SslModeStringTable) { if (e.mode == sm) { - result = e.string; + return QString::fromUtf8(e.string); } } - return result; + return {}; } -SslMode StringToSslMode(std::string s) +SslMode StringToSslMode(QString s) { SslMode result = SslMode::allow; for (auto e : SslModeStringTable) { @@ -43,14 +52,14 @@ SslMode StringToSslMode(std::string s) result = e.mode; } } - return result; + return {}; } -std::vector ConnectionConfig::s_keywords = { - "host", "hostaddr", "port", "user", "password", "dbname", - "sslmode", "sslcert", "sslkey", "sslrootcrt", "sslcrl", - "client_encoding", "application_name", nullptr }; +//std::vector ConnectionConfig::s_keywords = { +// "host", "hostaddr", "port", "user", "password", "dbname", +// "sslmode", "sslcert", "sslkey", "sslrootcrt", "sslcrl", +// "client_encoding", "application_name", nullptr }; ConnectionConfig::ConnectionConfig() @@ -83,7 +92,7 @@ const QUuid &ConnectionConfig::uuid() const } -void ConnectionConfig::setName(std::string desc) +void ConnectionConfig::setName(const QString& desc) { if (m_name != desc) { m_dirty = true; @@ -91,12 +100,12 @@ void ConnectionConfig::setName(std::string desc) } } -const std::string& ConnectionConfig::name() const +const QString& ConnectionConfig::name() const { return m_name; } -void ConnectionConfig::setHost(std::string host) +void ConnectionConfig::setHost(const QString& host) { if (m_host != host) { m_dirty = true; @@ -104,12 +113,12 @@ void ConnectionConfig::setHost(std::string host) } } -const std::string& ConnectionConfig::host() const +const QString& ConnectionConfig::host() const { return m_host; } -void ConnectionConfig::setHostAddr(std::string v) +void ConnectionConfig::setHostAddr(const QString &v) { if (m_hostaddr != v) { m_dirty = true; @@ -117,26 +126,25 @@ void ConnectionConfig::setHostAddr(std::string v) } } -const std::string& ConnectionConfig::hostAddr() const +const QString& ConnectionConfig::hostAddr() const { return m_hostaddr; } void ConnectionConfig::setPort(unsigned short port) { - auto p = std::to_string(port); - if (m_port != p) { + if (m_port != port) { m_dirty = true; - m_port = p; + m_port = port; } } unsigned short ConnectionConfig::port() const { - return static_cast(std::stoi(m_port)); + return m_port; } -void ConnectionConfig::setUser(std::string v) +void ConnectionConfig::setUser(const QString& v) { if (m_user != v) { m_dirty = true; @@ -145,12 +153,12 @@ void ConnectionConfig::setUser(std::string v) } -const std::string& ConnectionConfig::user() const +const QString& ConnectionConfig::user() const { return m_user; } -void ConnectionConfig::setPassword(std::string v) +void ConnectionConfig::setPassword(const QString& v) { if (m_password != v) { m_dirty = true; @@ -158,12 +166,12 @@ void ConnectionConfig::setPassword(std::string v) } } -const std::string& ConnectionConfig::password() const +const QString& ConnectionConfig::password() const { return m_password; } -void ConnectionConfig::setDbname(std::string v) +void ConnectionConfig::setDbname(const QString& v) { if (m_dbname != v) { m_dirty = true; @@ -171,26 +179,25 @@ void ConnectionConfig::setDbname(std::string v) } } -const std::string& ConnectionConfig::dbname() const +const QString& ConnectionConfig::dbname() const { return m_dbname; } void ConnectionConfig::setSslMode(SslMode m) { - auto v = SslModeToString(m); - if (m_sslMode != v) { + if (m_sslMode != m) { m_dirty = true; - m_sslMode = v; + m_sslMode = m; } } SslMode ConnectionConfig::sslMode() const { - return StringToSslMode(m_sslMode); + return m_sslMode; } -void ConnectionConfig::setSslCert(std::string v) +void ConnectionConfig::setSslCert(const QString& v) { if (m_sslCert != v) { m_dirty = true; @@ -198,12 +205,12 @@ void ConnectionConfig::setSslCert(std::string v) } } -const std::string& ConnectionConfig::sslCert() const +const QString& ConnectionConfig::sslCert() const { return m_sslCert; } -void ConnectionConfig::setSslKey(std::string v) +void ConnectionConfig::setSslKey(const QString& v) { if (m_sslKey != v) { m_dirty = true; @@ -211,12 +218,12 @@ void ConnectionConfig::setSslKey(std::string v) } } -const std::string& ConnectionConfig::sslKey() const +const QString& ConnectionConfig::sslKey() const { return m_sslKey; } -void ConnectionConfig::setSslRootCert(std::string v) +void ConnectionConfig::setSslRootCert(const QString& v) { if (m_sslRootCert != v) { m_dirty = true; @@ -224,12 +231,12 @@ void ConnectionConfig::setSslRootCert(std::string v) } } -const std::string& ConnectionConfig::sslRootCert() const +const QString& ConnectionConfig::sslRootCert() const { return m_sslRootCert; } -void ConnectionConfig::setSslCrl(std::string v) +void ConnectionConfig::setSslCrl(const QString& v) { if (m_sslCrl != v) { m_dirty = true; @@ -237,36 +244,36 @@ void ConnectionConfig::setSslCrl(std::string v) } } -const std::string& ConnectionConfig::sslCrl() const +const QString& ConnectionConfig::sslCrl() const { return m_sslCrl; } -const char * const * ConnectionConfig::getKeywords() const -{ - return s_keywords.data(); -} +//const char * const * ConnectionConfig::getKeywords() const +//{ +// return s_keywords.data(); +//} -const char * const * ConnectionConfig::getValues() const -{ - m_values.resize(s_keywords.size(), nullptr); - m_values[0] = valuePtr(m_host); - m_values[1] = valuePtr(m_hostaddr); - m_values[2] = valuePtr(m_port); - m_values[3] = valuePtr(m_user); - m_values[4] = valuePtr(m_password); - m_values[5] = valuePtr(m_dbname); - m_values[6] = valuePtr(m_sslMode); - m_values[7] = valuePtr(m_sslCert); - m_values[8] = valuePtr(m_sslKey); - m_values[9] = valuePtr(m_sslRootCert); - m_values[10] = valuePtr(m_sslCrl); - m_values[11] = "utf8"; - m_values[12] = valuePtr(m_applicationName); +//const char * const * ConnectionConfig::getValues() const +//{ +// m_values.resize(s_keywords.size(), nullptr); +// m_values[0] = valuePtr(m_host); +// m_values[1] = valuePtr(m_hostaddr); +// m_values[2] = valuePtr(m_port); +// m_values[3] = valuePtr(m_user); +// m_values[4] = valuePtr(m_password); +// m_values[5] = valuePtr(m_dbname); +// m_values[6] = valuePtr(m_sslMode); +// m_values[7] = valuePtr(m_sslCert); +// m_values[8] = valuePtr(m_sslKey); +// m_values[9] = valuePtr(m_sslRootCert); +// m_values[10] = valuePtr(m_sslCrl); +// m_values[11] = "utf8"; +// m_values[12] = valuePtr(m_applicationName); - return m_values.data(); -} +// return m_values.data(); +//} bool ConnectionConfig::isSameDatabase(const ConnectionConfig &rhs) const { @@ -290,28 +297,111 @@ void ConnectionConfig::clean() QString ConnectionConfig::makeLongDescription() const { - std::string result(name()); - result += " ("; - result += user(); - result += "@"; - result += host(); - result += ":"; - result += std::to_string(port()); - result += "/"; - result += dbname(); - result += ")"; - return stdStrToQ(result); + QString result; + result = name() % " (" % user() % "@" % host() % ":" % QString::number(port()) % "/" % dbname() % ")"; + return result; } -std::string ConnectionConfig::encodedPassword() const +QByteArray ConnectionConfig::encodedPassword() const { return m_encodedPassword; } -void ConnectionConfig::setEncodedPassword(const std::string &encodedPassword) +void ConnectionConfig::setEncodedPassword(const QByteArray &encodedPassword) { m_dirty = true; - m_encodedPassword = encodedPassword; + m_encodedPassword = encodedPassword; +} + +void ConnectionConfig::write(QDataStream &out) const +{ +// out << +} + +void ConnectionConfig::read(QDataStream &in) +{ + +} + +QString ConnectionConfig::escapeConnectionStringValue(const QString &value) +{ + bool contains_spaces = false; + int escapes = 0; + for (auto&& c : value) + if (c == ' ') contains_spaces = true; + else if (c == '\'' || c == '\\') ++escapes; + + if (contains_spaces || escapes > 0 || value.length() == 0) { + QString result; + result.reserve(2 + value.length() + escapes); + result += '\''; + for (auto&& c : value) { + if (c == '\'' || c == '\\') { + result += '\\'; + } + result += c; + } + result += '\''; + return result; + } + else { + return value; + } +} + +QString ConnectionConfig::connectionString() const +{ + QString s; + s += "host=" + % escapeConnectionStringValue(m_host) + % " port=" + % QString::number(m_port) + % " user=" + % escapeConnectionStringValue(m_user); + s += " password="; + s += escapeConnectionStringValue(m_password); + s += " dbname="; + s += escapeConnectionStringValue(m_dbname); + s += " sslmode="; + s += SslModeToString(m_sslMode); + if (!m_sslCert.isEmpty()) { + s += " sslcert="; + s += escapeConnectionStringValue(m_sslCert); + } + if (!m_sslKey.isEmpty()) { + s += " sslkey="; + s += escapeConnectionStringValue(m_sslKey); + } + if (!m_sslRootCert.isEmpty()) { + s += " sslrootcrt="; + s += escapeConnectionStringValue(m_sslRootCert); + } + if (!m_sslCrl.isEmpty()) { + s += " sslCrl="; + s += escapeConnectionStringValue(m_sslCrl); + } + s += " client_encoding=utf8"; + s += " application_name="; + s += escapeConnectionStringValue(m_applicationName); + + // "host", "hostaddr", "port", "user", "password", "dbname", + // "sslmode", "sslcert", "sslkey", "sslrootcrt", "sslcrl", + // "client_encoding", "application_name", nullptr }; + // m_values[0] = valuePtr(m_host); + // m_values[1] = valuePtr(m_hostaddr); + // m_values[2] = valuePtr(m_port); + // m_values[3] = valuePtr(m_user); + // m_values[4] = valuePtr(m_password); + // m_values[5] = valuePtr(m_dbname); + // m_values[6] = valuePtr(m_sslMode); + // m_values[7] = valuePtr(m_sslCert); + // m_values[8] = valuePtr(m_sslKey); + // m_values[9] = valuePtr(m_sslRootCert); + // m_values[10] = valuePtr(m_sslCrl); + // m_values[11] = "utf8"; + // m_values[12] = valuePtr(m_applicationName); + + return s; } /* @@ -347,11 +437,11 @@ void ConnectionConfig::writeToEnvironment(QProcessEnvironment &env) const { strToEnv(env, "PGHOST", m_host); strToEnv(env, "PGHOSTADDR", m_hostaddr); - strToEnv(env, "PGPORT", m_port); + strToEnv(env, "PGPORT", QString::number(m_port)); strToEnv(env, "PGDATABASE", m_dbname); strToEnv(env, "PGUSER", m_user); strToEnv(env, "PGPASSWORD", m_password); - strToEnv(env, "PGSSLMODE", m_sslMode); + strToEnv(env, "PGSSLMODE", SslModeToString(m_sslMode)); strToEnv(env, "PGSSLCERT", m_sslCert); strToEnv(env, "PGSSLKEY", m_sslKey); strToEnv(env, "PGSSLROOTCERT", m_sslRootCert); @@ -363,12 +453,12 @@ void ConnectionConfig::writeToEnvironment(QProcessEnvironment &env) const env.remove("PGREQUIRESSL"); } -void ConnectionConfig::strToEnv(QProcessEnvironment &env, const QString &var, const std::string &val) +void ConnectionConfig::strToEnv(QProcessEnvironment &env, const QString &var, const QString &val) { - if (val.empty()) + if (val.isEmpty()) env.remove(var); else - env.insert(var, stdStrToQ(val)); + env.insert(var, val); } void ConnectionGroup::erase(int idx, int count) @@ -389,3 +479,16 @@ void ConnectionGroup::update(int idx, const ConnectionConfig &cc) *node = cc; node->setParent(this); } + +QDataStream &operator<<(QDataStream &out, const ConnectionConfig &cc) +{ + cc.write(out); + return out; +} + +QDataStream &operator>>(QDataStream &in, ConnectionConfig &cc) +{ + //in>>myObj.uId>>myObj.passwd>>myObj.statusType; + cc.read(in); + return in; +} diff --git a/pglablib/ConnectionConfig.h b/pglablib/ConnectionConfig.h index 452e723..260087b 100644 --- a/pglablib/ConnectionConfig.h +++ b/pglablib/ConnectionConfig.h @@ -1,6 +1,9 @@ #ifndef CONNECTION_H #define CONNECTION_H +#include +#include +#include #include #include #include @@ -66,44 +69,44 @@ public: void setUuid(const QUuid &uuid); const QUuid &uuid() const; - void setName(std::string desc); - const std::string& name() const; + void setName(const QString& desc); + const QString& name() const; - void setHost(std::string host); - const std::string& host() const; + void setHost(const QString& host); + const QString& host() const; - void setHostAddr(std::string v); - const std::string& hostAddr() const; + void setHostAddr(const QString& v); + const QString& hostAddr() const; void setPort(unsigned short port); unsigned short port() const; - void setUser(std::string v); - const std::string& user() const; + void setUser(const QString& v); + const QString& user() const; - void setPassword(std::string v); - const std::string& password() const; + void setPassword(const QString& v); + const QString& password() const; - void setDbname(std::string v); - const std::string& dbname() const; + void setDbname(const QString& v); + const QString& dbname() const; void setSslMode(SslMode m); SslMode sslMode() const; - void setSslCert(std::string v); - const std::string& sslCert() const; + void setSslCert(const QString& v); + const QString& sslCert() const; - void setSslKey(std::string v); - const std::string& sslKey() const; + void setSslKey(const QString& v); + const QString& sslKey() const; - void setSslRootCert(std::string v); - const std::string& sslRootCert() const; + void setSslRootCert(const QString& v); + const QString& sslRootCert() const; - void setSslCrl(std::string v); - const std::string& sslCrl() const; + void setSslCrl(const QString& v); + const QString& sslCrl() const; - const char * const * getKeywords() const; - const char * const * getValues() const; +// const char * const * getKeywords() const; +// const char * const * getValues() const; bool isSameDatabase(const ConnectionConfig &rhs) const; @@ -115,38 +118,55 @@ public: bool operator==(QUuid id) const { return m_uuid == id; } QString makeLongDescription() const; - std::string encodedPassword() const; - void setEncodedPassword(const std::string &encodedPassword); + QByteArray encodedPassword() const; + void setEncodedPassword(const QByteArray &encodedPassword); + void write(QDataStream &out) const; + void read(QDataStream &in); + + /** Escapes a value for inclusion in a keyword value connection string. + * + * Unlikely it will be everneeded outside this class except for unit testing :) + */ + static QString escapeConnectionStringValue(const QString &value); + QString connectionString() const; private: QUuid m_uuid; - std::string m_name; - std::string m_host; - std::string m_hostaddr; - std::string m_port = "5432"; + QString m_name; + QString m_host; + QString m_hostaddr; + uint16_t m_port = 5432; - std::string m_user; - std::string m_password; ///< TODO do we want to keep this here or should we remember it seperatly? - std::string m_dbname; + QString m_user; + QString m_password; ///< Note this is not saved in the DB only the m_encodedPassword is safed. + QString m_dbname; - std::string m_sslMode; - std::string m_sslCert; - std::string m_sslKey; - std::string m_sslRootCert; - std::string m_sslCrl; + SslMode m_sslMode = SslMode::prefer; + QString m_sslCert; + QString m_sslKey; + QString m_sslRootCert; + QString m_sslCrl; - std::string m_applicationName; - std::string m_encodedPassword; + QString m_applicationName; + QByteArray m_encodedPassword; bool m_dirty = false; ConnectionGroup* m_group = nullptr; - static void strToEnv(QProcessEnvironment &env, const QString &var, const std::string &val); + static void strToEnv(QProcessEnvironment &env, const QString &var, const QString &val); + +// static std::vector s_keywords; +// mutable std::vector m_values; + - static std::vector s_keywords; - mutable std::vector m_values; }; +Q_DECLARE_METATYPE(ConnectionConfig) + +QDataStream &operator<<(QDataStream &out, const ConnectionConfig &cc); + +QDataStream &operator>>(QDataStream &in, ConnectionConfig &cc); + #endif // CONNECTION_H diff --git a/pglablib/catalog/PgKeywordList.cpp b/pglablib/catalog/PgKeywordList.cpp index ddbb1fe..45965cd 100644 --- a/pglablib/catalog/PgKeywordList.cpp +++ b/pglablib/catalog/PgKeywordList.cpp @@ -6,11 +6,120 @@ namespace { using KeywordHT = std::unordered_set; #define PG_KEYWORD(a,b,c) Keyword{a,c}, - const KeywordHT _ScanKeywords { + const KeywordHT _ScanKeywords = { //const Keyword _ScanKeywords[] = { #include }; + // The following keyword list are for plpgsql and are copied from the postgresql source. + // src\pl\plpgsql\src\pl_scanner.c + + static const KeywordHT plpgsql_reserved_keywords = { + PG_KEYWORD("all", K_ALL, RESERVED_KEYWORD) + PG_KEYWORD("begin", K_BEGIN, RESERVED_KEYWORD) + PG_KEYWORD("by", K_BY, RESERVED_KEYWORD) + PG_KEYWORD("case", K_CASE, RESERVED_KEYWORD) + PG_KEYWORD("declare", K_DECLARE, RESERVED_KEYWORD) + PG_KEYWORD("else", K_ELSE, RESERVED_KEYWORD) + PG_KEYWORD("end", K_END, RESERVED_KEYWORD) + PG_KEYWORD("execute", K_EXECUTE, RESERVED_KEYWORD) + PG_KEYWORD("for", K_FOR, RESERVED_KEYWORD) + PG_KEYWORD("foreach", K_FOREACH, RESERVED_KEYWORD) + PG_KEYWORD("from", K_FROM, RESERVED_KEYWORD) + PG_KEYWORD("if", K_IF, RESERVED_KEYWORD) + PG_KEYWORD("in", K_IN, RESERVED_KEYWORD) + PG_KEYWORD("into", K_INTO, RESERVED_KEYWORD) + PG_KEYWORD("loop", K_LOOP, RESERVED_KEYWORD) + PG_KEYWORD("not", K_NOT, RESERVED_KEYWORD) + PG_KEYWORD("null", K_NULL, RESERVED_KEYWORD) + PG_KEYWORD("or", K_OR, RESERVED_KEYWORD) + PG_KEYWORD("strict", K_STRICT, RESERVED_KEYWORD) + PG_KEYWORD("then", K_THEN, RESERVED_KEYWORD) + PG_KEYWORD("to", K_TO, RESERVED_KEYWORD) + PG_KEYWORD("using", K_USING, RESERVED_KEYWORD) + PG_KEYWORD("when", K_WHEN, RESERVED_KEYWORD) + PG_KEYWORD("while", K_WHILE, RESERVED_KEYWORD) + }; + + static const KeywordHT plpgsql_unreserved_keywords = { + PG_KEYWORD("absolute", K_ABSOLUTE, UNRESERVED_KEYWORD) + PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD) + PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD) + PG_KEYWORD("assert", K_ASSERT, UNRESERVED_KEYWORD) + PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD) + PG_KEYWORD("close", K_CLOSE, UNRESERVED_KEYWORD) + PG_KEYWORD("collate", K_COLLATE, UNRESERVED_KEYWORD) + PG_KEYWORD("column", K_COLUMN, UNRESERVED_KEYWORD) + PG_KEYWORD("column_name", K_COLUMN_NAME, UNRESERVED_KEYWORD) + PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD) + PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD) + PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD) + PG_KEYWORD("continue", K_CONTINUE, UNRESERVED_KEYWORD) + PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD) + PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD) + PG_KEYWORD("datatype", K_DATATYPE, UNRESERVED_KEYWORD) + PG_KEYWORD("debug", K_DEBUG, UNRESERVED_KEYWORD) + PG_KEYWORD("default", K_DEFAULT, UNRESERVED_KEYWORD) + PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD) + PG_KEYWORD("diagnostics", K_DIAGNOSTICS, UNRESERVED_KEYWORD) + PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD) + PG_KEYWORD("elseif", K_ELSIF, UNRESERVED_KEYWORD) + PG_KEYWORD("elsif", K_ELSIF, UNRESERVED_KEYWORD) + PG_KEYWORD("errcode", K_ERRCODE, UNRESERVED_KEYWORD) + PG_KEYWORD("error", K_ERROR, UNRESERVED_KEYWORD) + PG_KEYWORD("exception", K_EXCEPTION, UNRESERVED_KEYWORD) + PG_KEYWORD("exit", K_EXIT, UNRESERVED_KEYWORD) + PG_KEYWORD("fetch", K_FETCH, UNRESERVED_KEYWORD) + PG_KEYWORD("first", K_FIRST, UNRESERVED_KEYWORD) + PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD) + PG_KEYWORD("get", K_GET, UNRESERVED_KEYWORD) + PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD) + PG_KEYWORD("import", K_IMPORT, UNRESERVED_KEYWORD) + PG_KEYWORD("info", K_INFO, UNRESERVED_KEYWORD) + PG_KEYWORD("insert", K_INSERT, UNRESERVED_KEYWORD) + PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD) + PG_KEYWORD("last", K_LAST, UNRESERVED_KEYWORD) + PG_KEYWORD("log", K_LOG, UNRESERVED_KEYWORD) + PG_KEYWORD("message", K_MESSAGE, UNRESERVED_KEYWORD) + PG_KEYWORD("message_text", K_MESSAGE_TEXT, UNRESERVED_KEYWORD) + PG_KEYWORD("move", K_MOVE, UNRESERVED_KEYWORD) + PG_KEYWORD("next", K_NEXT, UNRESERVED_KEYWORD) + PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD) + PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD) + PG_KEYWORD("open", K_OPEN, UNRESERVED_KEYWORD) + PG_KEYWORD("option", K_OPTION, UNRESERVED_KEYWORD) + PG_KEYWORD("perform", K_PERFORM, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_context", K_PG_CONTEXT, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_datatype_name", K_PG_DATATYPE_NAME, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_exception_context", K_PG_EXCEPTION_CONTEXT, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT, UNRESERVED_KEYWORD) + PG_KEYWORD("print_strict_params", K_PRINT_STRICT_PARAMS, UNRESERVED_KEYWORD) + PG_KEYWORD("prior", K_PRIOR, UNRESERVED_KEYWORD) + PG_KEYWORD("query", K_QUERY, UNRESERVED_KEYWORD) + PG_KEYWORD("raise", K_RAISE, UNRESERVED_KEYWORD) + PG_KEYWORD("relative", K_RELATIVE, UNRESERVED_KEYWORD) + PG_KEYWORD("result_oid", K_RESULT_OID, UNRESERVED_KEYWORD) + PG_KEYWORD("return", K_RETURN, UNRESERVED_KEYWORD) + PG_KEYWORD("returned_sqlstate", K_RETURNED_SQLSTATE, UNRESERVED_KEYWORD) + PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD) + PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD) + PG_KEYWORD("rowtype", K_ROWTYPE, UNRESERVED_KEYWORD) + PG_KEYWORD("schema", K_SCHEMA, UNRESERVED_KEYWORD) + PG_KEYWORD("schema_name", K_SCHEMA_NAME, UNRESERVED_KEYWORD) + PG_KEYWORD("scroll", K_SCROLL, UNRESERVED_KEYWORD) + PG_KEYWORD("slice", K_SLICE, UNRESERVED_KEYWORD) + PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD) + PG_KEYWORD("stacked", K_STACKED, UNRESERVED_KEYWORD) + PG_KEYWORD("table", K_TABLE, UNRESERVED_KEYWORD) + PG_KEYWORD("table_name", K_TABLE_NAME, UNRESERVED_KEYWORD) + PG_KEYWORD("type", K_TYPE, UNRESERVED_KEYWORD) + PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD) + PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD) + PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD) + PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD) + }; + } const Keyword* getPgsqlKeyword(QString s) diff --git a/pglablib/util.h b/pglablib/util.h index 6fcfd96..fd9f510 100644 --- a/pglablib/util.h +++ b/pglablib/util.h @@ -19,7 +19,8 @@ inline QString stdStrToQ(const std::string &s) inline std::string qStrToStd(const QString &s) { - return std::string(s.toUtf8().data()); + auto ba = s.toUtf8(); + return std::string(ba.data(), ba.size()); } inline std::string qvarToStdStr(const QVariant &c) diff --git a/tests/pglabtests/pglabtests.pro b/tests/pglabtests/pglabtests.pro index 8b795b5..73c4847 100644 --- a/tests/pglabtests/pglabtests.pro +++ b/tests/pglabtests/pglabtests.pro @@ -17,6 +17,7 @@ SOURCES += main.cpp \ tst_ConvertLangToSqlString.cpp \ tst_ConvertToMultiLineCString.cpp \ tst_ExplainJsonParser.cpp \ + tst_escapeConnectionStringValue.cpp \ tst_expected.cpp \ tst_SqlLexer.cpp \ tst_scopeguard.cpp \ diff --git a/tests/pglabtests/tst_escapeConnectionStringValue.cpp b/tests/pglabtests/tst_escapeConnectionStringValue.cpp new file mode 100644 index 0000000..f3c6e10 --- /dev/null +++ b/tests/pglabtests/tst_escapeConnectionStringValue.cpp @@ -0,0 +1,57 @@ +#include +#include +#include "ConnectionConfig.h" +#include "PrintTo_Qt.h" + +using namespace testing; + + +TEST(escapeConnectionStringValue, emptyValue) +{ + auto input = QStringLiteral(""); + auto expected = QStringLiteral("''"); + + auto result = ConnectionConfig::escapeConnectionStringValue(input); + + ASSERT_EQ(result, expected); +} + +TEST(escapeConnectionStringValue, simpleValue) +{ + auto input = QStringLiteral("abc"); + auto expected = QStringLiteral("abc"); + + auto result = ConnectionConfig::escapeConnectionStringValue(input); + + ASSERT_EQ(result, expected); +} + +TEST(escapeConnectionStringValue, valueWithSpace) +{ + auto input = QStringLiteral("ab c"); + auto expected = QStringLiteral("'ab c'"); + + auto result = ConnectionConfig::escapeConnectionStringValue(input); + + ASSERT_EQ(result, expected); +} + +TEST(escapeConnectionStringValue, valueWithQuote) +{ + auto input = QStringLiteral("ab'c"); + auto expected = QStringLiteral("'ab\\'c'"); + + auto result = ConnectionConfig::escapeConnectionStringValue(input); + + ASSERT_EQ(result, expected); +} + +TEST(escapeConnectionStringValue, valueBackslash) +{ + auto input = QStringLiteral("ab\\c"); + auto expected = QStringLiteral("'ab\\\\c'"); + + auto result = ConnectionConfig::escapeConnectionStringValue(input); + + ASSERT_EQ(result, expected); +}