#pragma once #include #include #include #include #include #include #include namespace Pgsql { const Oid oid_bool = 16; const Oid oid_int2 = 21; const Oid oid_int4 = 23; const Oid oid_int8 = 20; const Oid oid_float4 = 700; const Oid oid_float8 = 701; const Oid oid_numeric = 1700; const Oid oid_oid = 26; class Connection; /* This library has multiple layers. Layer 1 delivers lowlevel C++ wrappers for the basic libpq functionality. Adding automatic resource management. */ // class ConnectionParams { // public: // std::string host; // std::string hostaddr; // unsigned short port = 5432; // std::string dbname; // std::string user; // std::string password; // int connect_timeout = -1; ///< -1 omit (ie uses default) // std::string application_name; // }; class ErrorDetails { public: static ErrorDetails createErrorDetailsFromPGresult(const PGresult *res); std::string errorMessage; std::string state; ///< PG_DIAG_SQLSTATE Error code as listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html std::string severity; std::string messagePrimary; std::string messageDetail; std::string messageHint; int statementPosition; ///< First character is one, measured in characters not bytes! int internalPosition; std::string internalQuery; std::string context; std::string schemaName; std::string tableName; std::string columnName; std::string datatypeName; std::string constraintName; std::string sourceFile; std::string sourceLine; std::string sourceFunction; }; class Value { public: Value(const char *val, Oid typ) : m_val(val), m_typ(typ) {} QString asQString() const { return QString::fromUtf8(m_val); } operator QString() const { return QString::fromUtf8(m_val); } operator std::string() const { return m_val; } operator short() const { return (short)std::atoi(m_val); } operator int() const { return std::atoi(m_val); } operator Oid() const { return operator int(); } operator __int64() const { return strtoull(m_val, nullptr, 10); } operator bool() const { return strcmp(m_val, "t") == 0; } private: const char *m_val; Oid m_typ; }; class Result; class Row { public: Row(const Result &result, int row) : m_result(result) , m_row(row) {} bool next(); bool operator==(const Row& rhs) { return &m_result == &rhs.m_result && m_row == rhs.m_row; } Value get(int col) const; //Value get(const char *colname) const; //bool get(int col, QString &s); private: const Result& m_result; int m_row; }; /** Non-copyable but movable wrapper for a postgresql result. */ class Result { public: class const_iterator { public: const_iterator(const Result &r, int rw) : m_row(r, rw) {} const_iterator operator++() { const_iterator t(*this); m_row.next(); return t; } const_iterator& operator++(int) { m_row.next(); return *this; } bool operator==(const const_iterator &rhs) { return m_row == rhs.m_row; } bool operator!=(const const_iterator &rhs) { return !operator==(rhs); } const Row& operator*() { return m_row; } const Row& operator->() { return m_row; } private: Row m_row; }; Result() = default; Result(PGresult *result); ~Result(); Result(const Result &rhs) = delete; Result& operator=(const Result &rhs) = delete; Result(Result &&rhs); Result& operator=(Result &&rhs); operator bool() const; ExecStatusType resultStatus(); std::string getResStatus(); /** Use this to retrieve an error code when this is an error result * * The possible code are listed in https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html */ std::string diagSqlState(); /** Retrieves all the error fields. */ ErrorDetails diagDetails(); const_iterator begin() const { return const_iterator(*this, 0); } const_iterator end() const { return const_iterator(*this, getRows()); } int tuplesAffected() const; int getRows() const; int getCols() const; const char* const getColName(int idx) const; const char * getVal(int col, int row) const; Value get(int col, int row) const; Oid type(int col) const; bool null(int col, int row) const; // iterator begin(); private: PGresult *result = nullptr; }; class Canceller { public: Canceller() = default; Canceller(PGcancel *c); Canceller(const Canceller&) = delete; Canceller& operator=(const Canceller&) = delete; Canceller(Canceller&& rhs); Canceller& operator=(Canceller&& rhs); ~Canceller(); bool cancel(std::string *error); private: PGcancel *m_cancel = nullptr; }; class Connection { public: Connection(); ~Connection(); Connection(const Connection &rhs) = delete; Connection& operator=(const Connection &rhs) = delete; Connection(Connection &&rhs); Connection& operator=(Connection &&rhs); // void connect(const ConnectionParams ¶ms); bool connect(const char *params); bool connect(const QString ¶ms) { return connect(params.toUtf8().data()); } bool connectStart(const char *params); bool connectStart(const std::string ¶ms) { return connectStart(params.c_str()); } bool connectStart(const QString ¶ms) { return connectStart(params.toUtf8().data()); } bool connectStart(const char * const *keywords, const char * const *values); PostgresPollingStatusType connectPoll(); ConnStatusType status(); int socket(); void close(); Canceller getCancel(); std::string getErrorMessage() const; Result query(const char * command); Result query(const QString &command) { return query(command.toUtf8().data()); } bool sendQuery(const char * query); bool sendQuery(const std::string &command) { return sendQuery(command.c_str()); } bool sendQuery(const QString &command) { return sendQuery(command.toUtf8().data()); } std::shared_ptr getResult(); bool consumeInput(); bool isBusy(); void setNoticeReceiver(std::function callback); private: PGconn *conn = nullptr; std::function notifyReceiver; static void notifyReceiveFunc(void *arg, const PGresult *result); }; class Field { public: std::string getName() const; private: //Tuples tuples; int field; // }; class Tuples { public: int getRowCount() const; int getColCount() const; Field getField(const std::string &fname); Field getField(const int idx); class const_iterator { public: const_iterator& operator++(); }; void rewind(); }; class OkResult: public Result { public: /** If the result is a data result then returns an interface for processing this data. The returned interface remains valid as long as this OkResult exists. */ Tuples* hasTuples(); }; // class ErrorResult: public Result { // // }; // class ITransaction { // public: // // Canceller Query(std::string query, // std::function on_success, // std::function on_cancelled, // std::function on_error); // // Canceller Query(std::string query, // std::function on_success, // std::function on_cancelled, // std::function on_error); // // // void Rollback( // std::function on_success, // std::function on_error); // void Commit( // std::function on_success, // std::function on_cancelled, // std::function on_error); // // }; }