Moved several files from pglab project to pglablib
This commit is contained in:
parent
206d734ff5
commit
f4538069cb
44 changed files with 45 additions and 44 deletions
|
|
@ -1,185 +0,0 @@
|
|||
#include "ASyncDBConnection.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include <chrono>
|
||||
|
||||
using namespace boost::asio;
|
||||
|
||||
//namespace {
|
||||
|
||||
// class registerMetaTypes {
|
||||
// public:
|
||||
// registerMetaTypes()
|
||||
// {
|
||||
// qRegisterMetaType<ASyncDBConnection::State>();
|
||||
// qRegisterMetaType<Pgsql::ErrorDetails>();
|
||||
// }
|
||||
// } registerMetaTypes_instance;
|
||||
|
||||
|
||||
//}
|
||||
|
||||
ASyncDBConnection::ASyncDBConnection(boost::asio::io_service &ios)
|
||||
: m_asioSock(ios)
|
||||
{}
|
||||
|
||||
ASyncDBConnection::~ASyncDBConnection() = default;
|
||||
|
||||
ASyncDBConnection::State ASyncDBConnection::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
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);
|
||||
// auto start = std::chrono::steady_clock::now();
|
||||
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.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*/)
|
||||
{
|
||||
// boost::asio::error::operation_aborted
|
||||
if (ec == boost::system::errc::success) {
|
||||
auto poll_state = m_connection.connectPoll();
|
||||
if (poll_state == PGRES_POLLING_OK) {
|
||||
// if connected return true
|
||||
doStateCallback(State::Connected);
|
||||
}
|
||||
else if (poll_state == PGRES_POLLING_FAILED) {
|
||||
doStateCallback(State::NotConnected);
|
||||
}
|
||||
else if (poll_state == PGRES_POLLING_READING) {
|
||||
doStateCallback(State::Connecting);
|
||||
m_asioSock.async_read_some(null_buffers(),
|
||||
[this] (boost::system::error_code ec, std::size_t s)
|
||||
{ async_connect_handler(ec, s); }
|
||||
);
|
||||
}
|
||||
else if (poll_state == PGRES_POLLING_WRITING) {
|
||||
doStateCallback(State::Connecting);
|
||||
m_asioSock.async_write_some(null_buffers(),
|
||||
[this] (boost::system::error_code ec, std::size_t s)
|
||||
{ async_connect_handler(ec, s); }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ASyncDBConnection::doStateCallback(State state)
|
||||
{
|
||||
m_state = state;
|
||||
if (state == State::Connected) {
|
||||
m_canceller = m_connection.getCancel();
|
||||
m_connection.setNoticeReceiver(
|
||||
[this](const PGresult *result) { processNotice(result); });
|
||||
}
|
||||
if (m_stateChangeReceiver)
|
||||
m_stateChangeReceiver(state);
|
||||
}
|
||||
|
||||
|
||||
void ASyncDBConnection::closeConnection()
|
||||
{
|
||||
// SHould this be async too????
|
||||
if (m_state == State::QuerySend) {
|
||||
m_canceller.cancel(nullptr);
|
||||
}
|
||||
if (m_state != State::NotConnected) {
|
||||
m_asioSock.close();
|
||||
m_connection.close();
|
||||
}
|
||||
doStateCallback(State::NotConnected);
|
||||
}
|
||||
|
||||
bool ASyncDBConnection::send(const std::string &command, on_result_callback on_result)
|
||||
{
|
||||
m_connection.sendQuery(command);
|
||||
m_timer.start();
|
||||
doStateCallback(State::QuerySend);
|
||||
m_asioSock.async_read_some(null_buffers(),
|
||||
[this, on_result] (boost::system::error_code ec, std::size_t s)
|
||||
{ async_query_handler(ec, s, on_result); }
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASyncDBConnection::send(const std::string &command, Pgsql::Params params, on_result_callback on_result)
|
||||
{
|
||||
m_connection.sendQueryParams(command.c_str(), params);
|
||||
m_timer.start();
|
||||
doStateCallback(State::QuerySend);
|
||||
m_asioSock.async_read_some(null_buffers(),
|
||||
[this, on_result] (boost::system::error_code ec, std::size_t s)
|
||||
{ async_query_handler(ec, s, on_result); }
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ASyncDBConnection::async_query_handler(boost::system::error_code ec, std::size_t /*s*/, on_result_callback on_result)
|
||||
{
|
||||
if (ec == boost::system::errc::success) {
|
||||
bool finished = false;
|
||||
if (m_connection.consumeInput()) {
|
||||
while ( ! finished && ! m_connection.isBusy()) {
|
||||
auto res = m_connection.getResult();
|
||||
qint64 ms = m_timer.restart();
|
||||
on_result(res, ms); // do we really want to send null result to???
|
||||
if (res == nullptr) {
|
||||
m_timer.invalidate();
|
||||
doStateCallback(State::Connected);
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
// else is still waiting for more data
|
||||
}
|
||||
else {
|
||||
// error during consume
|
||||
auto error_msg = m_connection.getErrorMessage();
|
||||
|
||||
}
|
||||
//return finished;
|
||||
if (!finished) {
|
||||
// wait for more
|
||||
m_asioSock.async_read_some(null_buffers(),
|
||||
[this, on_result] (boost::system::error_code ec, std::size_t s)
|
||||
{ async_query_handler(ec, s, on_result); }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ASyncDBConnection::cancel()
|
||||
{
|
||||
return m_canceller.cancel(nullptr);
|
||||
}
|
||||
|
||||
void ASyncDBConnection::processNotice(const PGresult *result)
|
||||
{
|
||||
Pgsql::ErrorDetails details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result);
|
||||
if (m_noticeReceiver)
|
||||
m_noticeReceiver(details);
|
||||
}
|
||||
|
||||
void ASyncDBConnection::setStateChangeReceiver(StateChangeReceiver state_change_receiver)
|
||||
{
|
||||
m_stateChangeReceiver = state_change_receiver;
|
||||
}
|
||||
|
||||
void ASyncDBConnection::setNoticeReceiver(NoticeReceiver notice_receiver)
|
||||
{
|
||||
m_noticeReceiver = notice_receiver;
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
#ifndef ASYNCDBCONNECTION_H
|
||||
#define ASYNCDBCONNECTION_H
|
||||
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Params.h"
|
||||
#include "Pgsql_Result.h"
|
||||
#include "Expected.h"
|
||||
#include "ConnectionConfig.h"
|
||||
#include <QElapsedTimer>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
|
||||
/** \brief Class that handles asynchronous execution of queries.
|
||||
*
|
||||
* Queries are passed to this class with a routine to call on completion
|
||||
* when the result is received that routine is called. The asynchronous
|
||||
* processing is done using boost::asio.
|
||||
*
|
||||
* You can cancel a running query but even then you have to wait for the result.
|
||||
*/
|
||||
class ASyncDBConnection {
|
||||
public:
|
||||
enum class State {
|
||||
NotConnected,
|
||||
Connecting,
|
||||
Connected, ///< connected and idle
|
||||
QuerySend, ///< connected query send expecting result
|
||||
CancelSend, ///< cancel send expecting result
|
||||
Terminating ///< shutting down
|
||||
};
|
||||
|
||||
using on_result_callback = std::function<void(Expected<std::shared_ptr<Pgsql::Result>>, qint64)>;
|
||||
|
||||
explicit ASyncDBConnection(boost::asio::io_service &ios);
|
||||
~ASyncDBConnection();
|
||||
|
||||
State state() const;
|
||||
void setupConnection(const ConnectionConfig &config);
|
||||
void closeConnection();
|
||||
|
||||
/** \defgroup send These function send queries to the server.
|
||||
*
|
||||
* The query string can actually contain multiple queries.
|
||||
* These functions report their results through a callback function.
|
||||
* If the command gives multiple results on_result will be called for each result.
|
||||
*
|
||||
* \note when the io_service that was passed to the constructor is running
|
||||
* on a different thread the callback also will be done on that thread. Forward
|
||||
* the call to your own thread if needed.
|
||||
*
|
||||
* \note while you can pass multiple queries to a single send call it is not allowed to
|
||||
* send new queries while not all results have been received.
|
||||
*/
|
||||
|
||||
/** \ingroup send
|
||||
* \brief Function to send a command without parameters to the server.
|
||||
*/
|
||||
bool send(const std::string &command, on_result_callback on_result);
|
||||
/** \ingroup send
|
||||
* \brief Function to send a a command with parameters to the server.
|
||||
*/
|
||||
bool send(const std::string &command, Pgsql::Params params, on_result_callback on_result);
|
||||
|
||||
bool cancel();
|
||||
|
||||
using StateChangeReceiver = std::function<void(ASyncDBConnection::State)>;
|
||||
void setStateChangeReceiver(StateChangeReceiver state_change_receiver);
|
||||
|
||||
using NoticeReceiver = std::function<void(Pgsql::ErrorDetails)>;
|
||||
void setNoticeReceiver(NoticeReceiver notice_receiver);
|
||||
|
||||
private:
|
||||
Pgsql::Connection m_connection;
|
||||
boost::asio::ip::tcp::socket m_asioSock;
|
||||
ConnectionConfig m_config;
|
||||
State m_state = State::NotConnected;
|
||||
Pgsql::Canceller m_canceller;
|
||||
StateChangeReceiver m_stateChangeReceiver;
|
||||
NoticeReceiver m_noticeReceiver;
|
||||
|
||||
QElapsedTimer m_timer;
|
||||
|
||||
void async_connect_handler(boost::system::error_code ec, std::size_t s);
|
||||
void async_query_handler(boost::system::error_code ec, std::size_t s, on_result_callback on_result);
|
||||
void doStateCallback(State state);
|
||||
void processNotice(const PGresult *result);
|
||||
};
|
||||
|
||||
#endif // ASYNCDBCONNECTION_H
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
#include "ConnectionConfig.h"
|
||||
#include "util.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
namespace {
|
||||
|
||||
struct {
|
||||
SslMode mode;
|
||||
const char* string;
|
||||
} SslModeStringTable[] = {
|
||||
{ SslMode::disable, "disable" },
|
||||
{ SslMode::allow, "allow" },
|
||||
{ SslMode::prefer, "prefer" },
|
||||
{ SslMode::require, "require" },
|
||||
{ SslMode::verify_ca, "verify-ca" },
|
||||
{ SslMode::verify_full, "verify-full" }
|
||||
};
|
||||
|
||||
inline const char *valuePtr(const std::string &v)
|
||||
{
|
||||
return v.empty() ? nullptr : v.c_str();
|
||||
}
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
std::string SslModeToString(SslMode sm)
|
||||
{
|
||||
std::string result;
|
||||
for (auto e : SslModeStringTable) {
|
||||
if (e.mode == sm) {
|
||||
result = e.string;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SslMode StringToSslMode(std::string s)
|
||||
{
|
||||
SslMode result = SslMode::allow;
|
||||
for (auto e : SslModeStringTable) {
|
||||
if (e.string == s) {
|
||||
result = e.mode;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<const char*> ConnectionConfig::s_keywords = {
|
||||
"host", "hostaddr", "port", "user", "password", "dbname",
|
||||
"sslmode", "sslcert", "sslkey", "sslrootcrt", "sslcrl",
|
||||
"client_encoding", "application_name", nullptr };
|
||||
|
||||
|
||||
ConnectionConfig::ConnectionConfig()
|
||||
: m_applicationName(QCoreApplication::applicationName().toUtf8().data())
|
||||
{}
|
||||
|
||||
void ConnectionConfig::setName(std::string desc)
|
||||
{
|
||||
if (m_name != desc) {
|
||||
m_dirty = true;
|
||||
m_name = std::move(desc);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setHost(std::string host)
|
||||
{
|
||||
if (m_host != host) {
|
||||
m_dirty = true;
|
||||
m_host = std::move(host);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::host() const
|
||||
{
|
||||
return m_host;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setHostAddr(std::string v)
|
||||
{
|
||||
if (m_hostaddr != v) {
|
||||
m_dirty = true;
|
||||
m_hostaddr = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::hostAddr() const
|
||||
{
|
||||
return m_hostaddr;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setPort(unsigned short port)
|
||||
{
|
||||
auto p = std::to_string(port);
|
||||
if (m_port != p) {
|
||||
m_dirty = true;
|
||||
m_port = p;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short ConnectionConfig::port() const
|
||||
{
|
||||
return static_cast<unsigned short>(std::stoi(m_port));
|
||||
}
|
||||
|
||||
void ConnectionConfig::setUser(std::string v)
|
||||
{
|
||||
if (m_user != v) {
|
||||
m_dirty = true;
|
||||
m_user = std::move(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::user() const
|
||||
{
|
||||
return m_user;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setPassword(std::string v)
|
||||
{
|
||||
if (m_password != v) {
|
||||
m_dirty = true;
|
||||
m_password = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::password() const
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setDbname(std::string v)
|
||||
{
|
||||
if (m_dbname != v) {
|
||||
m_dirty = true;
|
||||
m_dbname = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::dbname() const
|
||||
{
|
||||
return m_dbname;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setSslMode(SslMode m)
|
||||
{
|
||||
auto v = SslModeToString(m);
|
||||
if (m_sslMode != v) {
|
||||
m_dirty = true;
|
||||
m_sslMode = v;
|
||||
}
|
||||
}
|
||||
|
||||
SslMode ConnectionConfig::sslMode() const
|
||||
{
|
||||
return StringToSslMode(m_sslMode);
|
||||
}
|
||||
|
||||
void ConnectionConfig::setSslCert(std::string v)
|
||||
{
|
||||
if (m_sslCert != v) {
|
||||
m_dirty = true;
|
||||
m_sslCert = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslCert() const
|
||||
{
|
||||
return m_sslCert;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setSslKey(std::string v)
|
||||
{
|
||||
if (m_sslKey != v) {
|
||||
m_dirty = true;
|
||||
m_sslKey = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslKey() const
|
||||
{
|
||||
return m_sslKey;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setSslRootCert(std::string v)
|
||||
{
|
||||
if (m_sslRootCert != v) {
|
||||
m_dirty = true;
|
||||
m_sslRootCert = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslRootCert() const
|
||||
{
|
||||
return m_sslRootCert;
|
||||
}
|
||||
|
||||
void ConnectionConfig::setSslCrl(std::string v)
|
||||
{
|
||||
if (m_sslCrl != v) {
|
||||
m_dirty = true;
|
||||
m_sslCrl = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslCrl() const
|
||||
{
|
||||
return m_sslCrl;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
return m_values.data();
|
||||
}
|
||||
|
||||
bool ConnectionConfig::isSameDatabase(const ConnectionConfig &rhs) const
|
||||
{
|
||||
return m_host == rhs.m_host
|
||||
&& m_hostaddr == rhs.m_hostaddr
|
||||
&& m_port == rhs.m_port
|
||||
&& m_user == rhs.m_user
|
||||
&& m_password == rhs.m_password
|
||||
&& m_dbname == rhs.m_dbname;
|
||||
}
|
||||
|
||||
bool ConnectionConfig::dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
void ConnectionConfig::clean()
|
||||
{
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
PGHOST behaves the same as the host connection parameter.
|
||||
PGHOSTADDR behaves the same as the hostaddr connection parameter. This can be set instead of or in addition to PGHOST to avoid DNS lookup overhead.
|
||||
PGPORT behaves the same as the port connection parameter.
|
||||
PGDATABASE behaves the same as the dbname connection parameter.
|
||||
PGUSER behaves the same as the user connection parameter.
|
||||
PGPASSWORD behaves the same as the password connection parameter. Use of this environment variable is not recommended for security reasons, as some operating systems allow non-root users to see process environment variables via ps; instead consider using the ~/.pgpass file (see Section 31.15).
|
||||
PGPASSFILE specifies the name of the password file to use for lookups. If not set, it defaults to ~/.pgpass (see Section 31.15).
|
||||
PGSERVICE behaves the same as the service connection parameter.
|
||||
PGSERVICEFILE specifies the name of the per-user connection service file. If not set, it defaults to ~/.pg_service.conf (see Section 31.16).
|
||||
PGREALM sets the Kerberos realm to use with PostgreSQL, if it is different from the local realm. If PGREALM is set, libpq applications will attempt authentication with servers for this realm and use separate ticket files to avoid conflicts with local ticket files. This environment variable is only used if GSSAPI authentication is selected by the server.
|
||||
PGOPTIONS behaves the same as the options connection parameter.
|
||||
PGAPPNAME behaves the same as the application_name connection parameter.
|
||||
PGSSLMODE behaves the same as the sslmode connection parameter.
|
||||
PGREQUIRESSL behaves the same as the requiressl connection parameter.
|
||||
PGSSLCOMPRESSION behaves the same as the sslcompression connection parameter.
|
||||
PGSSLCERT behaves the same as the sslcert connection parameter.
|
||||
PGSSLKEY behaves the same as the sslkey connection parameter.
|
||||
PGSSLROOTCERT behaves the same as the sslrootcert connection parameter.
|
||||
PGSSLCRL behaves the same as the sslcrl connection parameter.
|
||||
PGREQUIREPEER behaves the same as the requirepeer connection parameter.
|
||||
PGKRBSRVNAME behaves the same as the krbsrvname connection parameter.
|
||||
PGGSSLIB behaves the same as the gsslib connection parameter.
|
||||
PGCONNECT_TIMEOUT behaves the same as the connect_timeout connection parameter.
|
||||
PGCLIENTENCODING behaves the same as the client_encoding connection parameter.
|
||||
|
||||
*/
|
||||
|
||||
void ConnectionConfig::writeToEnvironment(QProcessEnvironment &env) const
|
||||
{
|
||||
strToEnv(env, "PGHOST", m_host);
|
||||
strToEnv(env, "PGHOSTADDR", m_hostaddr);
|
||||
strToEnv(env, "PGPORT", m_port);
|
||||
strToEnv(env, "PGDATABASE", m_dbname);
|
||||
strToEnv(env, "PGUSER", m_user);
|
||||
strToEnv(env, "PGPASSWORD", m_password);
|
||||
strToEnv(env, "PGSSLMODE", m_sslMode);
|
||||
strToEnv(env, "PGSSLCERT", m_sslCert);
|
||||
strToEnv(env, "PGSSLKEY", m_sslKey);
|
||||
strToEnv(env, "PGSSLROOTCERT", m_sslRootCert);
|
||||
strToEnv(env, "PGSSLCRL", m_sslCrl);
|
||||
strToEnv(env, "PGSSLCOMPRESSION", "0");
|
||||
strToEnv(env, "PGCONNECT_TIMEOUT", "10");
|
||||
env.insert("PGCLIENTENCODING", "utf8");
|
||||
|
||||
env.remove("PGREQUIRESSL");
|
||||
}
|
||||
|
||||
void ConnectionConfig::strToEnv(QProcessEnvironment &env, const QString &var, const std::string &val)
|
||||
{
|
||||
if (val.empty())
|
||||
env.remove(var);
|
||||
else
|
||||
env.insert(var, stdStrToQ(val));
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
enum class SslMode {
|
||||
disable=0,
|
||||
allow=1,
|
||||
prefer=2,
|
||||
require=3,
|
||||
verify_ca=4,
|
||||
verify_full=5
|
||||
};
|
||||
|
||||
enum class PasswordMode {
|
||||
Unsave,
|
||||
Encrypted,
|
||||
DontSave
|
||||
};
|
||||
|
||||
class QProcessEnvironment;
|
||||
class QString;
|
||||
|
||||
class ConnectionConfig {
|
||||
public:
|
||||
ConnectionConfig();
|
||||
|
||||
void setName(std::string desc);
|
||||
const std::string& name() const;
|
||||
|
||||
void setHost(std::string host);
|
||||
const std::string& host() const;
|
||||
|
||||
void setHostAddr(std::string v);
|
||||
const std::string& hostAddr() const;
|
||||
|
||||
void setPort(unsigned short port);
|
||||
unsigned short port() const;
|
||||
|
||||
void setUser(std::string v);
|
||||
const std::string& user() const;
|
||||
|
||||
void setPassword(std::string v);
|
||||
const std::string& password() const;
|
||||
|
||||
void setDbname(std::string v);
|
||||
const std::string& dbname() const;
|
||||
|
||||
void setSslMode(SslMode m);
|
||||
SslMode sslMode() const;
|
||||
|
||||
void setSslCert(std::string v);
|
||||
const std::string& sslCert() const;
|
||||
|
||||
void setSslKey(std::string v);
|
||||
const std::string& sslKey() const;
|
||||
|
||||
void setSslRootCert(std::string v);
|
||||
const std::string& sslRootCert() const;
|
||||
|
||||
void setSslCrl(std::string v);
|
||||
const std::string& sslCrl() const;
|
||||
|
||||
const char * const * getKeywords() const;
|
||||
const char * const * getValues() const;
|
||||
|
||||
bool isSameDatabase(const ConnectionConfig &rhs) const;
|
||||
|
||||
void writeToEnvironment(QProcessEnvironment &env) const;
|
||||
|
||||
bool dirty() const;
|
||||
void clean();
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_host;
|
||||
std::string m_hostaddr;
|
||||
std::string m_port = "5432";
|
||||
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
std::string m_dbname;
|
||||
|
||||
std::string m_sslMode;
|
||||
std::string m_sslCert;
|
||||
std::string m_sslKey;
|
||||
std::string m_sslRootCert;
|
||||
std::string m_sslCrl;
|
||||
|
||||
std::string m_applicationName;
|
||||
|
||||
bool m_dirty = false;
|
||||
|
||||
static void strToEnv(QProcessEnvironment &env, const QString &var, const std::string &val);
|
||||
|
||||
static std::vector<const char*> s_keywords;
|
||||
mutable std::vector<const char*> m_values;
|
||||
};
|
||||
|
||||
|
||||
#endif // CONNECTION_H
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include "PgAttribute.h"
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef PGATTRIBUTE_H
|
||||
#define PGATTRIBUTE_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include <tuple>
|
||||
|
||||
class PgAttribute {
|
||||
public:
|
||||
using Key = std::tuple<Oid, int16_t>;
|
||||
|
||||
// Oid oid = InvalidOid;
|
||||
Oid relid = InvalidOid;
|
||||
QString name;
|
||||
Oid typid = InvalidOid;
|
||||
int32_t stattarget = 0;
|
||||
int16_t num = 0;
|
||||
int32_t ndims = 0; // array dimensions
|
||||
int32_t typmod = -1;
|
||||
bool notnull = false;
|
||||
bool hasdef = false;
|
||||
Oid collation = InvalidOid;
|
||||
QString acl;
|
||||
QString options;
|
||||
|
||||
QString defaultValue; ///< Comes from pg_attrdef table
|
||||
|
||||
|
||||
bool operator==(Key _k) const { return relid == std::get<0>(_k) && num == std::get<1>(_k); }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Key _k) const { return relid < std::get<0>(_k) || (relid == std::get<0>(_k) && num < std::get<1>(_k)); }
|
||||
bool operator<(const PgAttribute &rhs) const { return relid < rhs.relid || (relid == rhs.relid && num < rhs.num); }
|
||||
|
||||
};
|
||||
|
||||
#endif // PGATTRIBUTE_H
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#include "PgAttributeContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
//SELECT attname, pg_get_expr(adbin, adrelid) AS def_value
|
||||
//FROM pg_attribute
|
||||
// JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum
|
||||
//WHERE atthasdef=true
|
||||
|
||||
std::string PgAttributeContainer::getLoadQuery() const
|
||||
{
|
||||
return R"__(
|
||||
SELECT attrelid, attname, atttypid, attstattarget,
|
||||
attnum, attndims, atttypmod, attnotnull, atthasdef,
|
||||
attcollation, attacl, attoptions, pg_get_expr(adbin, adrelid) AS def_value
|
||||
FROM pg_catalog.pg_attribute
|
||||
LEFT JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum)__";
|
||||
}
|
||||
|
||||
PgAttribute PgAttributeContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgAttribute v;
|
||||
col >> v.relid >> v.name >> v.typid >> v.stattarget
|
||||
>> v.num >> v.ndims >> v.typmod >> v.notnull >> v.hasdef
|
||||
>> v.collation >> v.acl >> v.options >> v.defaultValue;
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<PgAttribute> PgAttributeContainer::getColumnsForRelation(Oid oid) const
|
||||
{
|
||||
std::vector<PgAttribute> result;
|
||||
for (const auto &e : m_container)
|
||||
if (e.relid == oid)
|
||||
result.push_back(e);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef PGATTRIBUTECONTAINER_H
|
||||
#define PGATTRIBUTECONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgAttribute.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
|
||||
class PgAttributeContainer : public PgContainer<PgAttribute, PgAttribute::Key> {
|
||||
public:
|
||||
using PgContainer<PgAttribute, PgAttribute::Key>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
|
||||
std::vector<PgAttribute> getColumnsForRelation(Oid oid) const;
|
||||
protected:
|
||||
PgAttribute loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
#endif // PGATTRIBUTECONTAINER_H
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#include "PgAuthId.h"
|
||||
|
||||
PgAuthId::PgAuthId() = default;
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef PGAUTHID_H
|
||||
#define PGAUTHID_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
class PgAuthId {
|
||||
public:
|
||||
PgAuthId();
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
bool super;
|
||||
bool inherit;
|
||||
bool createRole;
|
||||
bool createDB;
|
||||
bool canlogin;
|
||||
bool replication;
|
||||
bool bypassRls;
|
||||
int connLimit;
|
||||
QDateTime validUntil;
|
||||
|
||||
bool valid() const { return oid != InvalidOid; }
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgAuthId &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGAUTHID_H
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#include "PgAuthIdContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
std::string PgAuthIdContainer::getLoadQuery() const
|
||||
{
|
||||
std::string result =
|
||||
"SELECT oid, rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, "
|
||||
" rolcanlogin, rolreplication, rolconnlimit, rolvaliduntil";
|
||||
auto cat = m_catalogue.lock();
|
||||
if (cat && cat->serverVersion() >= 90500)
|
||||
result += ", rolbypassrls";
|
||||
|
||||
result += "\n"
|
||||
"FROM pg_authid";
|
||||
return result;
|
||||
}
|
||||
|
||||
void PgAuthIdContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
auto cat = m_catalogue.lock();
|
||||
bool with_rls = (cat && cat->serverVersion() >= 90500);
|
||||
for (auto row : res) {
|
||||
PgAuthId v;
|
||||
v.oid << row.get(0); // InvalidOid;
|
||||
v.name << row.get(1);
|
||||
v.super << row.get(2);
|
||||
v.inherit << row.get(3);
|
||||
v.createRole << row.get(4);
|
||||
v.createDB << row.get(5);
|
||||
v.canlogin << row.get(6);
|
||||
v.replication << row.get(7);
|
||||
v.connLimit << row.get(8);
|
||||
v.validUntil << row.get(9);
|
||||
v.bypassRls = with_rls ? (bool)row.get(10) : false;
|
||||
// QDateTime
|
||||
m_container.push_back(v);
|
||||
}
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef PGAUTHIDCONTAINER_H
|
||||
#define PGAUTHIDCONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include "PgContainer.h"
|
||||
#include "PgAuthId.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgAuthIdContainer: public PgContainer<PgAuthId> {
|
||||
public:
|
||||
using PgContainer<PgAuthId>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
virtual void load(const Pgsql::Result &res) override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGAUTHIDCONTAINER_H
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#include "PgClass.h"
|
||||
|
||||
void operator<<(RelPersistence &s, const Pgsql::Value &v)
|
||||
{
|
||||
//s = static_cast<T>(v);
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'p':
|
||||
s = RelPersistence::Permanent;
|
||||
break;
|
||||
case 'u':
|
||||
s = RelPersistence::Unlogged;
|
||||
break;
|
||||
case 't':
|
||||
s = RelPersistence::Temporary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void operator<<(RelKind &s, const Pgsql::Value &v)
|
||||
{
|
||||
//s = static_cast<T>(v);
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'r':
|
||||
s = RelKind::Table;
|
||||
break;
|
||||
case 'i':
|
||||
s = RelKind::Index;
|
||||
break;
|
||||
case 'S':
|
||||
s = RelKind::Sequence;
|
||||
break;
|
||||
case 'v':
|
||||
s = RelKind::View;
|
||||
break;
|
||||
case 'm':
|
||||
s = RelKind::MaterializedView;
|
||||
break;
|
||||
case 'c':
|
||||
s = RelKind::Composite;
|
||||
break;
|
||||
case 't':
|
||||
s = RelKind::Toast;
|
||||
break;
|
||||
case 'f':
|
||||
s = RelKind::ForeignTable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
#ifndef PGCLASS_H
|
||||
#define PGCLASS_H
|
||||
|
||||
#include "Pgsql_Value.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
enum class RelPersistence {
|
||||
Permanent, // p
|
||||
Unlogged, // u
|
||||
Temporary // t
|
||||
};
|
||||
|
||||
void operator<<(RelPersistence &s, const Pgsql::Value &v);
|
||||
|
||||
enum class RelKind {
|
||||
Table, // r
|
||||
Index, // i
|
||||
Sequence, // S
|
||||
View, // v
|
||||
MaterializedView, // m
|
||||
Composite, // c
|
||||
Toast, // t
|
||||
ForeignTable // f
|
||||
};
|
||||
|
||||
void operator<<(RelKind &s, const Pgsql::Value &v);
|
||||
|
||||
class PgClass {
|
||||
public:
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
Oid relnamespace = InvalidOid;
|
||||
Oid type = InvalidOid;
|
||||
Oid oftype = InvalidOid;
|
||||
Oid owner = InvalidOid;
|
||||
Oid am = InvalidOid;
|
||||
Oid filenode = InvalidOid;
|
||||
Oid tablespace = InvalidOid;
|
||||
int32_t pages_est = 0;
|
||||
float tuples_est = 0.0f;
|
||||
Oid toastrelid = InvalidOid;
|
||||
bool isshared = false;
|
||||
RelPersistence persistence;
|
||||
RelKind kind;
|
||||
bool hasoids = false;
|
||||
bool ispopulated;
|
||||
int frozenxid;
|
||||
int minmxid;
|
||||
QString acl;
|
||||
QString options;
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgClass &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
};
|
||||
|
||||
#endif // PGCLASS_H
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#include "PgClassContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
std::string PgClassContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid, relname, relnamespace, reltype, reloftype, "
|
||||
" relowner, relam, relfilenode, reltablespace, relpages, "
|
||||
" reltuples, reltoastrelid, relisshared, relpersistence, "
|
||||
" relkind, relhasoids, relispopulated, relfrozenxid, relminmxid, "
|
||||
" relacl, reloptions \n"
|
||||
"FROM pg_catalog.pg_class";
|
||||
}
|
||||
|
||||
PgClass PgClassContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgClass v;
|
||||
col >> v.oid >> v.name >> v.relnamespace >> v.type >> v.oftype
|
||||
>> v.owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est
|
||||
>> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence
|
||||
>> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid
|
||||
>> v.acl >> v.options;
|
||||
return v;
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef PGCLASSCONTAINER_H
|
||||
#define PGCLASSCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgClass.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgClassContainer: public PgContainer<PgClass> {
|
||||
public:
|
||||
using PgContainer<PgClass>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
protected:
|
||||
PgClass loadElem(const Pgsql::Row &row) override;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // PGCLASSCONTAINER_H
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#include "PgConstraint.h"
|
||||
|
||||
void operator<<(ConstraintType &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'c':
|
||||
s = ConstraintType::Check;
|
||||
break;
|
||||
case 'f':
|
||||
s = ConstraintType::ForeignKey;
|
||||
break;
|
||||
case 'p':
|
||||
s = ConstraintType::PrimaryKey;
|
||||
break;
|
||||
case 'u':
|
||||
s = ConstraintType::Unique;
|
||||
break;
|
||||
case 't':
|
||||
s = ConstraintType::ConstraintTrigger;
|
||||
break;
|
||||
case 'x':
|
||||
s = ConstraintType::ExclusionConstraint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'a':
|
||||
s = ForeignKeyAction::NoAction;
|
||||
break;
|
||||
case 'r':
|
||||
s = ForeignKeyAction::Restrict;
|
||||
break;
|
||||
case 'c':
|
||||
s = ForeignKeyAction::Cascade;
|
||||
break;
|
||||
case 'n':
|
||||
s = ForeignKeyAction::SetNull;
|
||||
break;
|
||||
case 'd':
|
||||
s = ForeignKeyAction::SetDefault;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v)
|
||||
{
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'f':
|
||||
s = ForeignKeyMatch::Full;
|
||||
break;
|
||||
case 'p':
|
||||
s = ForeignKeyMatch::Partial;
|
||||
break;
|
||||
case 's':
|
||||
s = ForeignKeyMatch::Simple;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PgConstraint::PgConstraint()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#ifndef PGCONSTRAINT_H
|
||||
#define PGCONSTRAINT_H
|
||||
|
||||
#include "Pgsql_Value.h"
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
enum class ConstraintType {
|
||||
Check, // c
|
||||
ForeignKey, // f
|
||||
PrimaryKey, // p
|
||||
Unique, // u
|
||||
ConstraintTrigger, // t
|
||||
ExclusionConstraint, // x
|
||||
};
|
||||
|
||||
void operator<<(ConstraintType &s, const Pgsql::Value &v);
|
||||
|
||||
|
||||
enum class ForeignKeyAction {
|
||||
NoAction, // a
|
||||
Restrict, // r
|
||||
Cascade, // c
|
||||
SetNull, // n
|
||||
SetDefault // d
|
||||
};
|
||||
|
||||
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v);
|
||||
|
||||
enum class ForeignKeyMatch {
|
||||
Full, // f
|
||||
Partial, // p
|
||||
Simple // s
|
||||
};
|
||||
|
||||
void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v);
|
||||
|
||||
class PgConstraint {
|
||||
public:
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
Oid connamespace = InvalidOid;
|
||||
ConstraintType type;
|
||||
bool deferrable;
|
||||
bool deferred;
|
||||
bool validated;
|
||||
Oid relid = InvalidOid; ///< the table this constraint is on
|
||||
Oid typid = InvalidOid;
|
||||
Oid indid = InvalidOid; ///< index supporting the constraint
|
||||
Oid frelid = InvalidOid; ///< only for FK, referenced table pg_class
|
||||
ForeignKeyAction fupdtype; // on update
|
||||
ForeignKeyAction fdeltype; // on delete
|
||||
ForeignKeyMatch fmatchtype; // match type
|
||||
bool islocal;
|
||||
int32_t inhcount;
|
||||
bool noinherit;
|
||||
std::vector<int16_t> key; // list of constraint columns attnum
|
||||
std::vector<int16_t> fkey; // fkey list of referenced columns
|
||||
std::vector<Oid> pfeqop;
|
||||
std::vector<Oid> ppeqop;
|
||||
std::vector<Oid> ffeqop;
|
||||
std::vector<Oid> exclop;
|
||||
QString bin;
|
||||
QString src;
|
||||
|
||||
QString definition;
|
||||
|
||||
PgConstraint();
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgConstraint &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGCONSTRAINT_H
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
#include "PgConstraintContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include <algorithm>
|
||||
|
||||
std::string PgConstraintContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q = R"__(
|
||||
SELECT oid, conname, connamespace, contype, condeferrable,
|
||||
condeferred, convalidated, conrelid, contypid, conindid,
|
||||
confrelid, confupdtype, confdeltype, confmatchtype,
|
||||
conislocal, coninhcount, connoinherit, conkey, confkey,
|
||||
conpfeqop, conppeqop, conffeqop, conexclop, conbin, consrc,
|
||||
pg_get_constraintdef(oid)
|
||||
FROM pg_constraint)__";
|
||||
|
||||
// auto cat = m_catalogue.lock();
|
||||
// if (cat && cat->serverVersion() >= 90400)
|
||||
// q += ", indisreplident ";
|
||||
// q += "\nFROM pg_index";
|
||||
return q;
|
||||
}
|
||||
|
||||
//void operator<<(std::vector<int16_t> &s, const Pgsql::Value &v)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
//void operator<<(std::vector<Oid> &s, const Pgsql::Value &v)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
PgConstraint PgConstraintContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgConstraint v;
|
||||
col >> v.oid >> v.name >> v.connamespace >> v.type >> v.deferrable
|
||||
>> v.deferred >> v.validated >> v.relid >> v.typid >> v.indid
|
||||
>> v.frelid >> v.fupdtype >> v.fdeltype >> v.fmatchtype
|
||||
>> v.islocal >> v.inhcount >> v.noinherit;
|
||||
col.getAsArray<int16_t>(std::back_inserter(v.key));
|
||||
col.getAsArray<int16_t>(std::back_inserter(v.fkey));
|
||||
col.getAsArray<Oid>(std::back_inserter(v.pfeqop));
|
||||
col.getAsArray<Oid>(std::back_inserter(v.ppeqop));
|
||||
col.getAsArray<Oid>(std::back_inserter(v.ffeqop));
|
||||
col.getAsArray<Oid>(std::back_inserter(v.exclop));
|
||||
col >> v.bin >> v.src >> v.definition;
|
||||
return v;
|
||||
}
|
||||
|
||||
const PgConstraint* PgConstraintContainer::getFKeyForTableColumn(Oid relid, int16_t attnum) const
|
||||
{
|
||||
const PgConstraint *result = nullptr;
|
||||
// WHat do we want to find here? On ly single column constraints or all contstraints.
|
||||
// auto res = std::find_if(m_container.begin(), m_container.end(),
|
||||
// [relid, attnum] (const auto &c) {
|
||||
// // the find on v.key may not look super efficient but remember it in general only has one or two elements.
|
||||
// return relid == c.relid &&
|
||||
// (std::find(attnum.begin(), attnum.end(), v.key) != attnum.end());
|
||||
// });
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef PGCONSTRAINTCONTAINER_H
|
||||
#define PGCONSTRAINTCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgConstraint.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
|
||||
class PgConstraintContainer : public PgContainer<PgConstraint> {
|
||||
public:
|
||||
using PgContainer<PgConstraint>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
//std::vector<PgConstraint> getIndexesForTable(Oid table_oid) const;
|
||||
const PgConstraint* getFKeyForTableColumn(Oid relid, int16_t attnum) const;
|
||||
protected:
|
||||
virtual PgConstraint loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
|
||||
#endif // PGCONSTRAINTCONTAINER_H
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include "PgContainer.h"
|
||||
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#ifndef PGCONTAINER_H
|
||||
#define PGCONTAINER_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include "Pgsql_Result.h"
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class IPgContainter {
|
||||
public:
|
||||
virtual ~IPgContainter() = default;
|
||||
|
||||
virtual std::string getLoadQuery() const = 0;
|
||||
virtual void load(const Pgsql::Result &res) = 0;
|
||||
};
|
||||
|
||||
template<typename T, typename K=Oid>
|
||||
class PgContainer: public IPgContainter {
|
||||
public:
|
||||
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||
|
||||
explicit PgContainer(std::weak_ptr<PgDatabaseCatalog> cat)
|
||||
: m_catalogue(cat)
|
||||
{}
|
||||
|
||||
|
||||
typename t_Container::const_iterator begin() const
|
||||
{
|
||||
return m_container.begin();
|
||||
}
|
||||
|
||||
typename t_Container::const_iterator end() const
|
||||
{
|
||||
return m_container.end();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_container.clear();
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
return (int)m_container.size();
|
||||
}
|
||||
|
||||
const T& getByKey(const K &key) const
|
||||
{
|
||||
auto lb_result = std::lower_bound(m_container.begin(), m_container.end(), key);
|
||||
if (lb_result != m_container.end() && *lb_result == key)
|
||||
return *lb_result;
|
||||
|
||||
return m_invalidInstance;
|
||||
}
|
||||
|
||||
const T& getByName(const QString &name) const
|
||||
{
|
||||
auto find_res = std::find(m_container.begin(), m_container.end(), name);
|
||||
|
||||
if (find_res != m_container.end())
|
||||
return *find_res;
|
||||
|
||||
return m_invalidInstance;
|
||||
}
|
||||
|
||||
const T& getByIdx(int idx) const
|
||||
{
|
||||
return m_container.at(idx);
|
||||
}
|
||||
|
||||
/** Override to implement complete loading logic.
|
||||
*
|
||||
* Do not override this function if you only want to implement
|
||||
* the loading of a single element. Override loadElem instead.
|
||||
*/
|
||||
virtual void load(const Pgsql::Result &res) override
|
||||
{
|
||||
m_container.clear();
|
||||
m_container.reserve(res.rows());
|
||||
for (auto row : res)
|
||||
m_container.push_back(loadElem(row));
|
||||
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
protected:
|
||||
std::weak_ptr<PgDatabaseCatalog> m_catalogue;
|
||||
t_Container m_container;
|
||||
|
||||
/** Override the implementation for this function to implement loading of single row.
|
||||
*
|
||||
* When overriding this function there is no need to override load.
|
||||
*/
|
||||
virtual T loadElem(const Pgsql::Row &) { return T(); }
|
||||
private:
|
||||
T m_invalidInstance;
|
||||
|
||||
};
|
||||
|
||||
#endif // PGCONTAINER_H
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#include "PgDatabase.h"
|
||||
|
||||
PgDatabase::PgDatabase()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef PGDATABASE_H
|
||||
#define PGDATABASE_H
|
||||
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgDatabase {
|
||||
public:
|
||||
PgDatabase();
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
Oid dba; // owner?
|
||||
int encoding;
|
||||
QString collate;
|
||||
QString ctype;
|
||||
bool isTemplate;
|
||||
bool allowConn;
|
||||
int connLimit;
|
||||
Oid tablespace;
|
||||
QString acl;//"ARRAY";"YES"
|
||||
|
||||
bool isValid() const { return oid != InvalidOid; }
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgDatabase &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGDATABASE_H
|
||||
|
|
@ -1,214 +0,0 @@
|
|||
#include "PgDatabaseCatalog.h"
|
||||
|
||||
#include "ASyncDBConnection.h"
|
||||
#include "PgAttributeContainer.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
#include "PgClassContainer.h"
|
||||
#include "PgConstraintContainer.h"
|
||||
#include "PgDatabaseContainer.h"
|
||||
#include "PgIndexContainer.h"
|
||||
#include "PgNamespaceContainer.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_oids.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
using namespace Pgsql;
|
||||
|
||||
QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
QString name;
|
||||
auto auth_ids = cat.authIds();
|
||||
if (auth_ids) {
|
||||
const PgAuthId& auth_id = auth_ids->getByKey(oid);
|
||||
if (auth_id.valid()) {
|
||||
name = auth_id.name;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
QString name = getRoleNameFromOid(cat, oid);
|
||||
return name;
|
||||
// return QString("%1 (%2)").arg(name).arg(oid);
|
||||
}
|
||||
|
||||
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
//QString name;
|
||||
auto nss = cat.namespaces();
|
||||
auto ns = nss->getByKey(oid);
|
||||
// if (auth_ids) {
|
||||
// const PgAuthId& auth_id = auth_ids->getByOid(oid);
|
||||
// if (auth_id.valid()) {
|
||||
// name = auth_id.name;
|
||||
// }
|
||||
// }
|
||||
//return name;
|
||||
// TODO load list and lookup name
|
||||
return ns.name; //QString("ns %1").arg(oid);
|
||||
|
||||
}
|
||||
|
||||
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||
{
|
||||
// TODO load list and lookup name
|
||||
return QString("ts %1").arg(oid);
|
||||
}
|
||||
|
||||
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod)
|
||||
{
|
||||
auto tc = cat.types();
|
||||
auto t = tc->getByKey(oid);
|
||||
QString s;
|
||||
if (t.category == TypCategory::Array) {
|
||||
// auto et = tc->getByKey(t.elem);
|
||||
// s = et.name;
|
||||
s = getTypeDisplayString(cat, t.elem, typmod);
|
||||
s += "[]";
|
||||
}
|
||||
else {
|
||||
s = t.name;
|
||||
switch (oid) {
|
||||
case varchar_oid:
|
||||
case char_oid:
|
||||
case text_oid:
|
||||
if (typmod > 4)
|
||||
s += QString::asprintf("(%d)", typmod-4);
|
||||
break;
|
||||
case numeric_oid:
|
||||
if (typmod > 4) {
|
||||
int prec = (typmod - 4) / 65536;
|
||||
int scale = (typmod - 4) % 65536;
|
||||
if (scale > 0)
|
||||
s += QString::asprintf("(%d,%d)", prec, scale);
|
||||
else
|
||||
s += QString::asprintf("(%d)", prec);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PgDatabaseCatalog::PgDatabaseCatalog()
|
||||
{
|
||||
}
|
||||
|
||||
PgDatabaseCatalog::~PgDatabaseCatalog()
|
||||
{
|
||||
}
|
||||
|
||||
void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn,
|
||||
std::function<bool(int, int)> progress_callback)
|
||||
{
|
||||
loadInfo(conn);
|
||||
if (progress_callback && !progress_callback(1, 9))
|
||||
return;
|
||||
load2(m_attributes, conn);
|
||||
if (progress_callback && !progress_callback(2, 9))
|
||||
return;
|
||||
load2(m_authIds, conn);
|
||||
if (progress_callback && !progress_callback(3, 9))
|
||||
return;
|
||||
load2(m_classes, conn);
|
||||
if (progress_callback && !progress_callback(4, 9))
|
||||
return;
|
||||
load2(m_constraints, conn);
|
||||
if (progress_callback && !progress_callback(5, 9))
|
||||
return;
|
||||
load2(m_databases, conn);
|
||||
if (progress_callback && !progress_callback(6, 9))
|
||||
return;
|
||||
load2(m_indexes, conn);
|
||||
if (progress_callback && !progress_callback(7, 9))
|
||||
return;
|
||||
load2(m_namespaces, conn);
|
||||
if (progress_callback && !progress_callback(8, 9))
|
||||
return;
|
||||
load2(m_types, conn);
|
||||
progress_callback && progress_callback(9, 9);
|
||||
}
|
||||
|
||||
void PgDatabaseCatalog::loadInfo(Pgsql::Connection &conn)
|
||||
{
|
||||
Pgsql::Result r = conn.query("SHOW server_version_num");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (r.rows() == 1)
|
||||
m_serverVersion << r.get(0, 0);
|
||||
|
||||
r = conn.query("SELECT version()");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
if (r.rows() == 1)
|
||||
m_serverVersionString = r.get(0, 0).asQString();
|
||||
}
|
||||
|
||||
void load(Pgsql::Connection &conn, IPgContainter &pg_cont)
|
||||
{
|
||||
//QThread::msleep(400);
|
||||
std::string q = pg_cont.getLoadQuery();
|
||||
Pgsql::Result result = conn.query(q.c_str());
|
||||
if (result && result.resultStatus() == PGRES_TUPLES_OK)
|
||||
pg_cont.load(result);
|
||||
else {
|
||||
auto details = result.diagDetails();
|
||||
|
||||
throw std::runtime_error("Query failed\n" + details.errorMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const QString& PgDatabaseCatalog::serverVersionString() const
|
||||
{
|
||||
return m_serverVersionString;
|
||||
}
|
||||
|
||||
int PgDatabaseCatalog::serverVersion() const
|
||||
{
|
||||
return m_serverVersion;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgAttributeContainer> PgDatabaseCatalog::attributes() const
|
||||
{
|
||||
return m_attributes;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgAuthIdContainer> PgDatabaseCatalog::authIds() const
|
||||
{
|
||||
return m_authIds;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgClassContainer> PgDatabaseCatalog::classes() const
|
||||
{
|
||||
return m_classes;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgConstraintContainer> PgDatabaseCatalog::constraints() const
|
||||
{
|
||||
return m_constraints;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgDatabaseContainer> PgDatabaseCatalog::databases() const
|
||||
{
|
||||
return m_databases;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgIndexContainer> PgDatabaseCatalog::indexes() const
|
||||
{
|
||||
return m_indexes;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgNamespaceContainer> PgDatabaseCatalog::namespaces() const
|
||||
{
|
||||
return m_namespaces;
|
||||
}
|
||||
|
||||
std::shared_ptr<const PgTypeContainer> PgDatabaseCatalog::types() const
|
||||
{
|
||||
return m_types;
|
||||
}
|
||||
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
#ifndef PGSQLDATABASECATALOGUE_H
|
||||
#define PGSQLDATABASECATALOGUE_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Connection;
|
||||
|
||||
}
|
||||
|
||||
class PgAttributeContainer;
|
||||
class PgAuthIdContainer;
|
||||
class PgClassContainer;
|
||||
class PgConstraintContainer;
|
||||
class PgDatabaseContainer;
|
||||
class PgIndexContainer;
|
||||
class PgNamespaceContainer;
|
||||
class PgTypeContainer;
|
||||
|
||||
class PgDatabaseCatalog: public std::enable_shared_from_this<PgDatabaseCatalog> {
|
||||
public:
|
||||
PgDatabaseCatalog();
|
||||
PgDatabaseCatalog(const PgDatabaseCatalog&) = delete;
|
||||
PgDatabaseCatalog& operator = (const PgDatabaseCatalog&) = delete;
|
||||
~PgDatabaseCatalog();
|
||||
|
||||
void loadAll(Pgsql::Connection &conn,
|
||||
std::function<bool(int, int)> progress_callback);
|
||||
|
||||
void loadInfo(Pgsql::Connection &conn);
|
||||
|
||||
const QString& serverVersionString() const;
|
||||
int serverVersion() const;
|
||||
|
||||
std::shared_ptr<const PgAttributeContainer> attributes() const;
|
||||
std::shared_ptr<const PgAuthIdContainer> authIds() const;
|
||||
std::shared_ptr<const PgClassContainer> classes() const;
|
||||
std::shared_ptr<const PgConstraintContainer> constraints() const;
|
||||
std::shared_ptr<const PgDatabaseContainer> databases() const;
|
||||
std::shared_ptr<const PgIndexContainer> indexes() const;
|
||||
std::shared_ptr<const PgNamespaceContainer> namespaces() const;
|
||||
std::shared_ptr<const PgTypeContainer> types() const;
|
||||
private:
|
||||
QString m_serverVersionString;
|
||||
int m_serverVersion;
|
||||
|
||||
std::shared_ptr<PgAttributeContainer> m_attributes;
|
||||
std::shared_ptr<PgAuthIdContainer> m_authIds;
|
||||
std::shared_ptr<PgClassContainer> m_classes;
|
||||
std::shared_ptr<PgConstraintContainer> m_constraints;
|
||||
std::shared_ptr<PgDatabaseContainer> m_databases;
|
||||
std::shared_ptr<PgIndexContainer> m_indexes;
|
||||
std::shared_ptr<PgNamespaceContainer> m_namespaces;
|
||||
std::shared_ptr<PgTypeContainer> m_types;
|
||||
|
||||
template <typename T>
|
||||
void load2(std::shared_ptr<T> &ptr, Pgsql::Connection &conn)
|
||||
{
|
||||
if (!ptr)
|
||||
ptr = std::make_shared<T>(shared_from_this());
|
||||
|
||||
load(conn, *ptr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
QString getRoleNameFromOid(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod = -1);
|
||||
|
||||
|
||||
#endif // PGSQLDATABASECATALOGUE_H
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#include "PgDatabaseContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "Pgsql_Col.h"
|
||||
|
||||
|
||||
std::string PgDatabaseContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid,datname,datdba,encoding,datcollate,datctype,datistemplate,datallowconn,"
|
||||
"datconnlimit,dattablespace,datacl FROM pg_database";
|
||||
}
|
||||
|
||||
void PgDatabaseContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
for (auto row : res) {
|
||||
Pgsql::Col col(row);
|
||||
PgDatabase v;
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef PGDATABASECONTAINER_H
|
||||
#define PGDATABASECONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgDatabase.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PgDatabaseContainer: public PgContainer<PgDatabase> {
|
||||
public:
|
||||
//explicit PgDatabaseContainer(PgDatabaseCatalogue *cat);
|
||||
using PgContainer<PgDatabase>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
virtual void load(const Pgsql::Result &res) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGDATABASECONTAINER_H
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#include "PgIndex.h"
|
||||
|
||||
PgIndex::PgIndex() = default;
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef PGINDEX_H
|
||||
#define PGINDEX_H
|
||||
|
||||
#include "Pgsql_declare.h"
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
class PgIndex {
|
||||
public:
|
||||
|
||||
Oid indexrelid = InvalidOid;
|
||||
Oid relid = InvalidOid;
|
||||
int16_t natts = 0;
|
||||
bool isunique = false;
|
||||
bool isprimary = false;
|
||||
bool isexclusion = false;
|
||||
bool immediate = false;
|
||||
bool isclustered = false;
|
||||
bool isvalid = false;
|
||||
bool checkxmin = false;
|
||||
bool isready = false;
|
||||
bool islive = false;
|
||||
bool isreplident = false;
|
||||
std::vector<int16_t> key;
|
||||
std::vector<Oid> collation;
|
||||
std::vector<Oid> indclass;
|
||||
std::vector<int16_t> option;
|
||||
QString exprs;
|
||||
QString pred;
|
||||
QString definition;
|
||||
|
||||
PgIndex();
|
||||
|
||||
bool operator==(Oid _oid) const { return indexrelid == _oid; }
|
||||
//bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return indexrelid < _oid; }
|
||||
bool operator<(const PgIndex &rhs) const { return indexrelid < rhs.indexrelid; }
|
||||
};
|
||||
|
||||
#endif // PGINDEX_H
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#include "PgIndexContainer.h"
|
||||
#include "PgDatabaseCatalog.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include <iterator>
|
||||
|
||||
std::string PgIndexContainer::getLoadQuery() const
|
||||
{
|
||||
std::string q = R"__(
|
||||
SELECT indexrelid, indrelid, indnatts, indisunique, indisprimary,
|
||||
indisexclusion, indimmediate, indisclustered, indisvalid,
|
||||
indcheckxmin, indisready, indislive, indkey,
|
||||
indcollation, indclass, indoption, indexprs, indpred,
|
||||
pg_get_indexdef(indexrelid))__";
|
||||
|
||||
auto cat = m_catalogue.lock();
|
||||
if (cat && cat->serverVersion() >= 90400)
|
||||
q += ", indisreplident ";
|
||||
q += "\nFROM pg_index";
|
||||
return q;
|
||||
}
|
||||
|
||||
PgIndex PgIndexContainer::loadElem(const Pgsql::Row &row)
|
||||
{
|
||||
Pgsql::Col col(row);
|
||||
PgIndex v;
|
||||
col >> v.indexrelid >> v.relid >> v.natts >> v.isunique
|
||||
>> v.isprimary >> v.isexclusion >> v.immediate >> v.isclustered
|
||||
>> v.isvalid >> v.checkxmin >> v.isready >> v.islive;
|
||||
col.getAsVector<int16_t>(std::back_inserter(v.key));
|
||||
col.getAsVector<Oid>(std::back_inserter(v.collation));
|
||||
col.getAsVector<Oid>(std::back_inserter(v.indclass));
|
||||
col.getAsVector<int16_t>(std::back_inserter(v.option));
|
||||
col >> v.exprs >> v.pred >> v.definition;
|
||||
auto cat = m_catalogue.lock();
|
||||
if (cat && cat->serverVersion() >= 90400)
|
||||
col >> v.isreplident;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<PgIndex> PgIndexContainer::getIndexesForTable(Oid table_oid) const
|
||||
{
|
||||
std::vector<PgIndex> result;
|
||||
for (const auto &e : m_container)
|
||||
if (e.relid == table_oid)
|
||||
result.push_back(e);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef PGINDEXCONTAINER_H
|
||||
#define PGINDEXCONTAINER_H
|
||||
|
||||
#include "PgContainer.h"
|
||||
#include "PgIndex.h"
|
||||
#include "Pgsql_declare.h"
|
||||
#include <vector>
|
||||
|
||||
class PgIndexContainer : public PgContainer<PgIndex> {
|
||||
public:
|
||||
using PgContainer<PgIndex>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
std::vector<PgIndex> getIndexesForTable(Oid table_oid) const;
|
||||
protected:
|
||||
virtual PgIndex loadElem(const Pgsql::Row &row) override;
|
||||
};
|
||||
|
||||
#endif // PGINDEXCONTAINER_H
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#include "PgNamespace.h"
|
||||
|
||||
PgNamespace::PgNamespace() = default;
|
||||
|
||||
bool PgNamespace::isSystemCatalog() const
|
||||
{
|
||||
return name == "pg_catalog"
|
||||
|| name == "pg_toast"
|
||||
|| name == "pg_temp_1"
|
||||
|| name == "pg_toast_temp_1"
|
||||
|| name == "information_schema";
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef PGNAMESPACE_H
|
||||
#define PGNAMESPACE_H
|
||||
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgNamespace {
|
||||
public:
|
||||
PgNamespace();
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;
|
||||
Oid owner = InvalidOid;
|
||||
QString acl;
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgNamespace &rhs) const { return oid < rhs.oid; }
|
||||
|
||||
bool isSystemCatalog() const;
|
||||
};
|
||||
|
||||
#endif // PGNAMESPACE_H
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#include "PgNamespaceContainer.h"
|
||||
#include "Pgsql_Col.h"
|
||||
#include "Pgsql_Result.h"
|
||||
#include "Pgsql_Value.h"
|
||||
|
||||
std::string PgNamespaceContainer::getLoadQuery() const
|
||||
{
|
||||
return "SELECT oid, nspname, nspowner, nspacl FROM pg_catalog.pg_namespace";
|
||||
}
|
||||
|
||||
void PgNamespaceContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
for (auto row : res) {
|
||||
Pgsql::Col col(row);
|
||||
PgNamespace v;
|
||||
col >> v.oid >> v.name >> v.owner >> v.acl;
|
||||
m_container.push_back(v);
|
||||
}
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef PGNAMESPACECONTAINER_H
|
||||
#define PGNAMESPACECONTAINER_H
|
||||
|
||||
#include "PgNamespace.h"
|
||||
#include "PgContainer.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
class PgNamespaceContainer: public PgContainer<PgNamespace> {
|
||||
public:
|
||||
using PgContainer<PgNamespace>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
virtual void load(const Pgsql::Result &res) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // PGNAMESPACECONTAINER_H
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include "PgType.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
|
||||
void operator<<(TypCategory &s, const Pgsql::Value &v)
|
||||
{
|
||||
//s = static_cast<T>(v);
|
||||
const char *c = v.c_str();
|
||||
switch (*c) {
|
||||
case 'A':
|
||||
s = TypCategory::Array;
|
||||
break;
|
||||
case 'B':
|
||||
s = TypCategory::Boolean;
|
||||
break;
|
||||
case 'D':
|
||||
s = TypCategory::DateTime;
|
||||
break;
|
||||
case 'E':
|
||||
s = TypCategory::Enum;
|
||||
break;
|
||||
case 'G':
|
||||
s = TypCategory::Geometric;
|
||||
break;
|
||||
case 'I':
|
||||
s = TypCategory::NetworkAddress;
|
||||
break;
|
||||
case 'N':
|
||||
s = TypCategory::Numeric;
|
||||
break;
|
||||
case 'P':
|
||||
s = TypCategory::Pseudo;
|
||||
break;
|
||||
case 'R':
|
||||
s = TypCategory::Range;
|
||||
break;
|
||||
case 'S':
|
||||
s = TypCategory::String;
|
||||
break;
|
||||
case 'T':
|
||||
s = TypCategory::Timespan;
|
||||
break;
|
||||
case 'U':
|
||||
s = TypCategory::UserDefined;
|
||||
break;
|
||||
case 'V':
|
||||
s = TypCategory::BitString;
|
||||
break;
|
||||
case 'X':
|
||||
s = TypCategory::Unknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PgType::PgType() = default;
|
||||
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#ifndef PGTYPE_H
|
||||
#define PGTYPE_H
|
||||
|
||||
#include <QString>
|
||||
#include <libpq-fe.h>
|
||||
#include "Pgsql_Value.h"
|
||||
|
||||
enum class TypCategory {
|
||||
Array,
|
||||
Boolean,
|
||||
Composite,
|
||||
DateTime,
|
||||
Enum,
|
||||
Geometric,
|
||||
NetworkAddress,
|
||||
Numeric,
|
||||
Pseudo,
|
||||
Range,
|
||||
String,
|
||||
Timespan,
|
||||
UserDefined,
|
||||
BitString,
|
||||
Unknown
|
||||
};
|
||||
|
||||
void operator<<(TypCategory &s, const Pgsql::Value &v);
|
||||
|
||||
|
||||
class PgType {
|
||||
public:
|
||||
PgType();
|
||||
|
||||
Oid oid = InvalidOid;
|
||||
QString name;//"name";"NO"
|
||||
Oid typnamespace = InvalidOid;//"oid";"NO"
|
||||
Oid owner = InvalidOid;//"oid";"NO"
|
||||
short len = -1;//"smallint";"NO"
|
||||
bool byval = false;//"boolean";"NO"
|
||||
QString type;//""char"";"NO"
|
||||
TypCategory category;//""char"";"NO"
|
||||
bool ispreferred = false;//"boolean";"NO"
|
||||
bool isdefined = false;//"boolean";"NO"
|
||||
QString delim;//""char"";"NO"
|
||||
Oid relid = InvalidOid;//"oid";"NO"
|
||||
Oid elem = InvalidOid;//"oid";"NO"
|
||||
Oid array = InvalidOid;//"oid";"NO"
|
||||
QString input;//regproc";"NO"
|
||||
QString output;//"regproc";"NO"
|
||||
QString receive;//"regproc";"NO"
|
||||
QString send;//"regproc";"NO"
|
||||
QString modin;//"regproc";"NO"
|
||||
QString modout;//"regproc";"NO"
|
||||
QString analyze;//"regproc";"NO"
|
||||
QString align;//""char"";"NO"
|
||||
QString storage;//""char"";"NO"
|
||||
bool notnull = false;//"boolean";"NO"
|
||||
Oid basetype = InvalidOid;//"oid";"NO"
|
||||
int typmod = -1;//"integer";"NO"
|
||||
int ndims = 0;//"integer";"NO"
|
||||
Oid collation = InvalidOid;//"oid";"NO"
|
||||
QString defaultbin;//"pg_node_tree";"YES"
|
||||
QString typdefault;//"text";"YES"
|
||||
QString acl;//"ARRAY";"YES"
|
||||
|
||||
bool operator==(Oid _oid) const { return oid == _oid; }
|
||||
bool operator==(const QString &n) const { return name == n; }
|
||||
bool operator<(Oid _oid) const { return oid < _oid; }
|
||||
bool operator<(const PgType &rhs) const { return oid < rhs.oid; }
|
||||
};
|
||||
|
||||
#endif // PGTYPE_H
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include "PgTypeContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include <algorithm>
|
||||
|
||||
//const PgType& PgTypeContainer::getTypeByOid(Oid oid) const
|
||||
//{
|
||||
// auto lb_result = std::lower_bound(m_types.begin(), m_types.end(), oid);
|
||||
// if (lb_result != m_types.end() && lb_result->oid == oid)
|
||||
// return *lb_result;
|
||||
|
||||
// return m_invalidType;
|
||||
//}
|
||||
|
||||
//const PgType& PgTypeContainer::getTypeByName(const QString &name) const
|
||||
//{
|
||||
// auto find_res = std::find(m_types.begin(), m_types.end(), name);
|
||||
|
||||
// if (find_res != m_types.end())
|
||||
// return *find_res;
|
||||
|
||||
// return m_invalidType;
|
||||
//}
|
||||
|
||||
//const PgType& PgTypeContainer::getTypeByIdx(int idx) const
|
||||
//{
|
||||
// return m_types.at(idx);
|
||||
//}
|
||||
|
||||
std::string PgTypeContainer::getLoadQuery() const
|
||||
{
|
||||
return
|
||||
"SELECT oid, typname, typnamespace, typowner, typlen, typbyval, typtype, typcategory, \n"
|
||||
" typispreferred, typisdefined, typdelim, typrelid, typelem, typarray, typinput, typoutput, \n"
|
||||
" typreceive, typsend, typmodin, typmodout, typanalyze, typalign, typstorage, typnotnull, \n"
|
||||
" typbasetype, typtypmod, typndims, typcollation, typdefaultbin, typdefault, typacl \n"
|
||||
"FROM pg_type";
|
||||
}
|
||||
|
||||
void PgTypeContainer::load(const Pgsql::Result &res)
|
||||
{
|
||||
const int n_rows = res.rows();
|
||||
m_container.clear();
|
||||
m_container.reserve(n_rows);
|
||||
for (auto row : res) {
|
||||
PgType v;
|
||||
v.oid << row.get(0); // InvalidOid;
|
||||
v.name << row.get(1); //. operator QString(); // "name";"NO"
|
||||
v.typnamespace << row.get(2); // InvalidOid;//"oid";"NO"
|
||||
v.owner << row.get(3); // InvalidOid;//"oid";"NO"
|
||||
v.len << row.get(4); // -1;//"smallint";"NO"
|
||||
v.byval << row.get(5); // false;//"boolean";"NO"
|
||||
v.type << row.get(6);//""char"";"NO"
|
||||
v.category << row.get(7);//""char"";"NO"
|
||||
v.ispreferred << row.get(8); //false;//"boolean";"NO"
|
||||
v.isdefined << row.get(9); //false;//"boolean";"NO"
|
||||
v.delim << row.get(10); //""char"";"NO"
|
||||
v.relid << row.get(11); // InvalidOid;//"oid";"NO"
|
||||
v.elem << row.get(12); // InvalidOid;//"oid";"NO"
|
||||
v.array << row.get(13); // InvalidOid;//"oid";"NO"
|
||||
v.input << row.get(14);//regproc";"NO"
|
||||
v.output << row.get(15);//"regproc";"NO"
|
||||
v.receive << row.get(16);//"regproc";"NO"
|
||||
v.send << row.get(17);//"regproc";"NO"
|
||||
v.modin << row.get(18);//"regproc";"NO"
|
||||
v.modout << row.get(19);//"regproc";"NO"
|
||||
v.analyze << row.get(20);//"regproc";"NO"
|
||||
v.align << row.get(21); // //""char"";"NO"
|
||||
v.storage << row.get(22); //""char"";"NO"
|
||||
v.notnull << row.get(23); //"boolean";"NO"
|
||||
v.basetype << row.get(24); //"oid";"NO"
|
||||
v.typmod << row.get(25); //-1;//"integer";"NO"
|
||||
v.ndims << row.get(26); //"integer";"NO"
|
||||
v.collation << row.get(27); //InvalidOid;//"oid";"NO"
|
||||
v.defaultbin << row.get(28);//"pg_node_tree";"YES"
|
||||
v.typdefault << row.get(29);//"text";"YES"
|
||||
v.acl << row.get(30);//"ARRAY";"YES"
|
||||
m_container.push_back(v);
|
||||
}
|
||||
std::sort(m_container.begin(), m_container.end());
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef PGTYPECONTAINER_H
|
||||
#define PGTYPECONTAINER_H
|
||||
|
||||
#include "PgType.h"
|
||||
#include "PgContainer.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Result;
|
||||
|
||||
}
|
||||
|
||||
class PgTypeContainer: public PgContainer<PgType> {
|
||||
public:
|
||||
using PgContainer<PgType>::PgContainer;
|
||||
|
||||
virtual std::string getLoadQuery() const override;
|
||||
virtual void load(const Pgsql::Result &res) override;
|
||||
|
||||
/** Searches for the type matching the specified oid.
|
||||
*
|
||||
* \return Returns the matching type or if it is not found a default constructed PgType (oid == InvalidOid).
|
||||
*/
|
||||
// const PgType& getTypeByOid(Oid oid) const;
|
||||
// const PgType& getTypeByName(const QString &name) const;
|
||||
// const PgType& getTypeByIdx(int idx) const;
|
||||
private:
|
||||
// PgType m_invalidType; ///< default constructed object for when a non existent type is being retrieved.
|
||||
// t_Types m_types; // Keep sorted by Oid
|
||||
};
|
||||
|
||||
#endif // PGTYPECONTAINER_H
|
||||
|
|
@ -32,23 +32,16 @@ win32:RC_ICONS += pglab.ico
|
|||
SOURCES += main.cpp\
|
||||
QueryResultModel.cpp \
|
||||
QueryExplainModel.cpp \
|
||||
ASyncDBConnection.cpp \
|
||||
tsqueue.cpp \
|
||||
CreateDatabaseDialog.cpp \
|
||||
DatabaseWindow.cpp \
|
||||
ConnectionManagerWindow.cpp \
|
||||
ConnectionListModel.cpp \
|
||||
ConnectionConfig.cpp \
|
||||
BackupRestore.cpp \
|
||||
QueryTab.cpp \
|
||||
stopwatch.cpp \
|
||||
util.cpp \
|
||||
DatabaseInspectorWidget.cpp \
|
||||
PgType.cpp \
|
||||
PgTypeContainer.cpp \
|
||||
TuplesResultWidget.cpp \
|
||||
PgNamespace.cpp \
|
||||
PgClass.cpp \
|
||||
BackupDialog.cpp \
|
||||
TypeSelectionItemModel.cpp \
|
||||
MasterController.cpp \
|
||||
|
|
@ -59,11 +52,7 @@ SOURCES += main.cpp\
|
|||
ServerWindow.cpp \
|
||||
ASyncWindow.cpp \
|
||||
DatabasesTableModel.cpp \
|
||||
PgDatabase.cpp \
|
||||
PgDatabaseContainer.cpp \
|
||||
RolesTableModel.cpp \
|
||||
PgAuthId.cpp \
|
||||
PgAuthIdContainer.cpp \
|
||||
ConnectionList.cpp \
|
||||
ProcessStdioWidget.cpp \
|
||||
GlobalIoService.cpp \
|
||||
|
|
@ -72,40 +61,23 @@ SOURCES += main.cpp\
|
|||
BaseTableModel.cpp \
|
||||
QueryParamListController.cpp \
|
||||
TablesPage.cpp \
|
||||
PgClassContainer.cpp \
|
||||
TablesTableModel.cpp \
|
||||
PgDatabaseCatalog.cpp \
|
||||
PgNamespaceContainer.cpp \
|
||||
ColumnTableModel.cpp \
|
||||
PgAttribute.cpp \
|
||||
PgContainer.cpp \
|
||||
PgAttributeContainer.cpp \
|
||||
PgIndex.cpp \
|
||||
PgIndexContainer.cpp \
|
||||
PgConstraint.cpp \
|
||||
PgConstraintContainer.cpp \
|
||||
NamespaceFilterWidget.cpp \
|
||||
NamespaceItemModel.cpp
|
||||
|
||||
HEADERS += \
|
||||
QueryResultModel.h \
|
||||
QueryExplainModel.h \
|
||||
ASyncDBConnection.h \
|
||||
tsqueue.h \
|
||||
CreateDatabaseDialog.h \
|
||||
DatabaseWindow.h \
|
||||
ConnectionManagerWindow.h \
|
||||
ConnectionListModel.h \
|
||||
ConnectionConfig.h \
|
||||
QueryTab.h \
|
||||
stopwatch.h \
|
||||
util.h \
|
||||
DatabaseInspectorWidget.h \
|
||||
PgType.h \
|
||||
PgTypeContainer.h \
|
||||
TuplesResultWidget.h \
|
||||
PgNamespace.h \
|
||||
PgClass.h \
|
||||
BackupDialog.h \
|
||||
TypeSelectionItemModel.h \
|
||||
MasterController.h \
|
||||
|
|
@ -116,12 +88,7 @@ HEADERS += \
|
|||
ServerWindow.h \
|
||||
ASyncWindow.h \
|
||||
DatabasesTableModel.h \
|
||||
PgDatabase.h \
|
||||
PgDatabaseContainer.h \
|
||||
PgContainer.h \
|
||||
RolesTableModel.h \
|
||||
PgAuthId.h \
|
||||
PgAuthIdContainer.h \
|
||||
ConnectionList.h \
|
||||
ProcessStdioWidget.h \
|
||||
GlobalIoService.h \
|
||||
|
|
@ -130,17 +97,8 @@ HEADERS += \
|
|||
BaseTableModel.h \
|
||||
QueryParamListController.h \
|
||||
TablesPage.h \
|
||||
PgClassContainer.h \
|
||||
TablesTableModel.h \
|
||||
PgDatabaseCatalog.h \
|
||||
PgNamespaceContainer.h \
|
||||
ColumnTableModel.h \
|
||||
PgAttribute.h \
|
||||
PgAttributeContainer.h \
|
||||
PgIndex.h \
|
||||
PgIndexContainer.h \
|
||||
PgConstraint.h \
|
||||
PgConstraintContainer.h \
|
||||
NamespaceFilterWidget.h \
|
||||
NamespaceItemModel.h
|
||||
|
||||
|
|
|
|||
148
pglab/util.cpp
148
pglab/util.cpp
|
|
@ -1,148 +0,0 @@
|
|||
#include "util.h"
|
||||
#include "CsvWriter.h"
|
||||
#include <QApplication>
|
||||
#include <QTextStream>
|
||||
#include <QClipboard>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
// Supported range from microseconds to seconds
|
||||
// min:sec to hours::min::sec
|
||||
QString msfloatToHumanReadableString(float ms)
|
||||
{
|
||||
QString unit;
|
||||
float val;
|
||||
int deci = 2;
|
||||
if (ms < 1.0f) {
|
||||
val = ms * 1000.f;
|
||||
//result = QString::asprintf("%0.3f", ms * 1000.0f);
|
||||
unit = u8"μs";
|
||||
}
|
||||
else if (ms >= 1000.0) {
|
||||
val = ms / 1000.0f;
|
||||
unit = "s";
|
||||
if (val >= 60.0) {
|
||||
int secs = val;
|
||||
int min = secs / 60.0;
|
||||
secs -= min * 60;
|
||||
if (min >= 60) {
|
||||
int hour = min / 60;
|
||||
min -= hour * 60;
|
||||
return QString::asprintf("%d:%02d:%02d", hour, min, secs);
|
||||
}
|
||||
else {
|
||||
return QString::asprintf("%02d:%02d", min, secs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val = ms;
|
||||
unit = "ms";
|
||||
}
|
||||
|
||||
// if (val >= 1000.f) {
|
||||
// deci = 0;
|
||||
// }
|
||||
// else
|
||||
if (val >= 100.f) {
|
||||
deci = 0;
|
||||
}
|
||||
else if (val >= 10.f) {
|
||||
deci = 1;
|
||||
}
|
||||
QString result = QString::asprintf("%0.*f", deci, val);
|
||||
return result + unit;
|
||||
}
|
||||
|
||||
void exportTable(const QTableView *view, QTextStream &out)
|
||||
{
|
||||
auto model = view->model();
|
||||
if (model) {
|
||||
CsvWriter csv(&out);
|
||||
csv.setSeperator('\t');
|
||||
csv.setQuote('"');
|
||||
|
||||
const int cols = model->columnCount();
|
||||
const int rows = model->rowCount();
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
for (int col = 0; col < cols; ++col) {
|
||||
auto idx = model->index(row, col);
|
||||
auto display_text = idx.data(Qt::DisplayRole).toString();
|
||||
csv.writeField(display_text);
|
||||
}
|
||||
csv.nextRow();
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
void copySelectionToClipboard(const QTableView *view)
|
||||
{
|
||||
//QAbstractItemModel * model = resultModel; //view->model();
|
||||
QItemSelectionModel * selection = view->selectionModel();
|
||||
|
||||
QModelIndexList selectedIndexes = selection->selectedIndexes();
|
||||
|
||||
if (selectedIndexes.count() > 0) {
|
||||
QString clipboard_string;
|
||||
QTextStream out(&clipboard_string, QIODevice::WriteOnly);
|
||||
CsvWriter csv(&out);
|
||||
csv.setSeperator('\t');
|
||||
csv.setQuote('"');
|
||||
|
||||
int previous_row = selectedIndexes[0].row();
|
||||
// for (int i = 0; i < selectedIndexes.count(); ++i) {
|
||||
// QModelIndex current = selectedIndexes[i];
|
||||
for (auto current : selectedIndexes) {
|
||||
if (current.row() > previous_row) {
|
||||
csv.nextRow();
|
||||
previous_row = current.row();
|
||||
}
|
||||
QString display_text = current.data(Qt::DisplayRole).toString();
|
||||
csv.writeField(display_text);
|
||||
}
|
||||
out.flush();
|
||||
QApplication::clipboard()->setText(clipboard_string);
|
||||
}
|
||||
}
|
||||
|
||||
QString ConvertToMultiLineCString(const QString &in)
|
||||
{
|
||||
// We need to atleast escape " and \ and also any multi byte utf8 char
|
||||
|
||||
QString out;
|
||||
out.append('"');
|
||||
QByteArray ba = in.toUtf8();
|
||||
for (auto c : ba) {
|
||||
if (c == '\\') {
|
||||
out.append("\\\\");
|
||||
}
|
||||
else if (c == '"') {
|
||||
out.append("\\\"");
|
||||
}
|
||||
else if (uchar(c) > 127) {
|
||||
out.append(QString("\\x%1").arg(uchar(c), 2, 16, QChar('0')));
|
||||
}
|
||||
else if (c == '\n') {
|
||||
// at end of line we add a space and a new line in the string then we put in the end quote go to the next line and put the open quote
|
||||
out.append(" \\n\"\n\"");
|
||||
}
|
||||
else {
|
||||
out.append(c);
|
||||
}
|
||||
}
|
||||
out.append('"');
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
QString ConvertToMultiLineRawCppString(const QString &in)
|
||||
{
|
||||
const QString delim = "__SQL__";
|
||||
|
||||
QString out;
|
||||
out.append("R\"" + delim + "(\n");
|
||||
out.append(in.trimmed());
|
||||
out.append("\n)" + delim + "\"");
|
||||
return out;
|
||||
}
|
||||
44
pglab/util.h
44
pglab/util.h
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <string>
|
||||
#include <QString>
|
||||
#include <QTableView>
|
||||
|
||||
QString msfloatToHumanReadableString(float ms);
|
||||
void copySelectionToClipboard(const QTableView *view);
|
||||
QString ConvertToMultiLineCString(const QString &in);
|
||||
QString ConvertToMultiLineRawCppString(const QString &in);
|
||||
void exportTable(const QTableView *view, QTextStream &out);
|
||||
|
||||
inline QString stdStrToQ(const std::string &s)
|
||||
{
|
||||
return QString::fromUtf8(s.c_str());
|
||||
}
|
||||
|
||||
inline std::string qStrToStd(const QString &s)
|
||||
{
|
||||
return std::string(s.toUtf8().data());
|
||||
}
|
||||
|
||||
inline std::string qvarToStdStr(const QVariant &c)
|
||||
{
|
||||
return qStrToStd(c.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<QString>
|
||||
{
|
||||
std::size_t operator()(const QString& s) const
|
||||
{
|
||||
return qHash(s);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // UTIL_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue