File indexing completed on 2024-05-05 16:47:14
0001 /* This file is part of the KDE project 0002 Copyright (C) 2005 Adam Pigg <adam@piggz.co.uk> 0003 Copyright (C) 2010-2016 Jarosław Staniek <staniek@kde.org> 0004 0005 This program is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this program; see the file COPYING. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #ifndef KDB_POSTGRESQLCONNECTION_P_H 0022 #define KDB_POSTGRESQLCONNECTION_P_H 0023 0024 #include "KDbConnection_p.h" 0025 #include "PostgresqlConnection.h" 0026 #include "PostgresqlDriver.h" 0027 #include "KDbResult.h" 0028 #include "KDbSqlField.h" 0029 #include "KDbSqlRecord.h" 0030 #include "KDbSqlResult.h" 0031 #include "KDbSqlString.h" 0032 0033 #include <QString> 0034 0035 #include <libpq-fe.h> 0036 0037 class KDbEscapedString; 0038 0039 class PostgresqlConnectionInternal : public KDbConnectionInternal 0040 { 0041 public: 0042 explicit PostgresqlConnectionInternal(KDbConnection *connection); 0043 0044 virtual ~PostgresqlConnectionInternal(); 0045 0046 //! Executes query for a raw SQL statement @a sql on the database 0047 PGresult* executeSql(const KDbEscapedString& sql); 0048 0049 static QString serverResultName(int resultCode); 0050 0051 void storeResultAndClear(KDbResult *result, PGresult **pgResult, ExecStatusType execStatus); 0052 0053 void storeResult(KDbResult *result); 0054 0055 //! @return true if status of connection is "OK". 0056 /*! From https://www.postgresql.org/docs/8.4/static/libpq-status.html: 0057 "Only two of these are seen outside of an asynchronous connection procedure: 0058 CONNECTION_OK and CONNECTION_BAD." */ 0059 inline bool connectionOK() { return CONNECTION_OK == PQstatus(conn); } 0060 0061 PGconn *conn; 0062 bool unicode; 0063 QByteArray escapingBuffer; 0064 bool fuzzystrmatchExtensionCreated = false; 0065 private: 0066 Q_DISABLE_COPY(PostgresqlConnectionInternal) 0067 }; 0068 0069 //! Internal PostgreSQL cursor data. 0070 /*! Provides a low-level abstraction for iterating over result sets. */ 0071 class PostgresqlCursorData : public PostgresqlConnectionInternal 0072 { 0073 public: 0074 explicit PostgresqlCursorData(KDbConnection* connection); 0075 ~PostgresqlCursorData() override; 0076 0077 PGresult* res; 0078 ExecStatusType resultStatus; 0079 private: 0080 Q_DISABLE_COPY(PostgresqlCursorData) 0081 }; 0082 0083 class PostgresqlSqlField : public KDbSqlField 0084 { 0085 public: 0086 inline PostgresqlSqlField(const PGresult *r, int n) : result(r), number(n) { 0087 } 0088 //! @return column name 0089 inline QString name() override { 0090 //! @todo UTF8? 0091 return QString::fromLatin1(PQfname(result, number)); 0092 } 0093 inline int type() override { 0094 return static_cast<int>(PQftype(result, number)); 0095 } 0096 inline int length() override { 0097 return PostgresqlDriver::pqfmodToLength(PQfmod(result, number)); 0098 } 0099 const PGresult * const result; 0100 const int number; 0101 private: 0102 Q_DISABLE_COPY(PostgresqlSqlField) 0103 }; 0104 0105 class PostgresqlSqlRecord : public KDbSqlRecord 0106 { 0107 public: 0108 inline PostgresqlSqlRecord(const PGresult *res, int r) : result(res), record(r) { 0109 } 0110 inline ~PostgresqlSqlRecord() override { 0111 } 0112 inline QString stringValue(int index) override { 0113 return PQgetisnull(result, record, index) 0114 ? QString() 0115 : QString::fromUtf8(PQgetvalue(result, record, index), 0116 PQgetlength(result, record, index)); 0117 } 0118 inline KDbSqlString cstringValue(int index) override { 0119 return PQgetisnull(result, record, index) 0120 ? KDbSqlString() 0121 : KDbSqlString(PQgetvalue(result, record, index), 0122 PQgetlength(result, record, index)); 0123 } 0124 inline QByteArray toByteArray(int index) override { 0125 return PQgetisnull(result, record, index) 0126 ? QByteArray() 0127 : QByteArray(PQgetvalue(result, record, index), 0128 PQgetlength(result, record, index)); 0129 } 0130 0131 private: 0132 const PGresult * const result; 0133 const int record; 0134 Q_DISABLE_COPY(PostgresqlSqlRecord) 0135 }; 0136 0137 class PostgresqlSqlResult : public KDbSqlResult 0138 { 0139 public: 0140 inline PostgresqlSqlResult(PostgresqlConnection *c, PGresult* r, ExecStatusType status) 0141 : conn(c), result(r), resultStatus(status), recordToFetch(0), recordsCount(PQntuples(r)) 0142 { 0143 Q_ASSERT(c); 0144 } 0145 0146 inline ~PostgresqlSqlResult() override { 0147 PQclear(result); 0148 } 0149 0150 inline KDbConnection *connection() const override { 0151 return conn; 0152 } 0153 0154 inline int fieldsCount() override { 0155 return PQnfields(result); 0156 } 0157 0158 inline Q_REQUIRED_RESULT KDbSqlField *field(int index) override 0159 { 0160 return new PostgresqlSqlField(result, index); 0161 } 0162 0163 Q_REQUIRED_RESULT KDbField *createField(const QString &tableName, int index) override; 0164 0165 inline Q_REQUIRED_RESULT QSharedPointer<KDbSqlRecord> fetchRecord() override 0166 { 0167 return QSharedPointer<KDbSqlRecord>(recordToFetch < recordsCount 0168 ? new PostgresqlSqlRecord(result, recordToFetch++) 0169 : nullptr); 0170 } 0171 0172 inline KDbResult lastResult() override { 0173 KDbResult r; 0174 if (resultStatus == PGRES_TUPLES_OK || resultStatus == PGRES_COMMAND_OK) { 0175 return r; 0176 } 0177 QByteArray msg(PQresultErrorMessage(result)); 0178 if (msg.endsWith('\n')) { 0179 msg.chop(1); 0180 } 0181 r.setServerMessage(QString::fromLatin1(msg)); 0182 r.setServerErrorCode(resultStatus); 0183 return r; 0184 } 0185 0186 //! @return the oid of the last insert - only works if there was insert of 1 row 0187 inline quint64 lastInsertRecordId() override { 0188 // InvalidOid == 0 means error 0189 const Oid oid = PQoidValue(result); 0190 return oid == 0 ? std::numeric_limits<quint64>::max() : static_cast<quint64>(oid); 0191 } 0192 0193 private: 0194 //! @return a KDb type for PostgreSQL type 0195 //! @todo prompt user if necessary? 0196 KDbField::Type type(const QString& tableName, PostgresqlSqlField *field); 0197 0198 PostgresqlConnection* const conn; 0199 PGresult* result; 0200 ExecStatusType resultStatus; 0201 int recordToFetch; 0202 int recordsCount; 0203 Q_DISABLE_COPY(PostgresqlSqlResult) 0204 }; 0205 0206 #endif