File indexing completed on 2024-04-28 15:58:50
0001 /* This file is part of the KDE project 0002 Copyright (C) 2004 Martin Ellis <martin.ellis@kdemail.net> 0003 Copyright (C) 2004-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_MYSQLCONNECTION_P_H 0022 #define KDB_MYSQLCONNECTION_P_H 0023 0024 #include "KDbConnection_p.h" 0025 #include "MysqlConnection.h" 0026 #include "KDbResult.h" 0027 #include "KDbSqlField.h" 0028 #include "KDbSqlRecord.h" 0029 #include "KDbSqlResult.h" 0030 #include "KDbSqlString.h" 0031 0032 #include <mysql.h> 0033 0034 class KDbConnectionData; 0035 class KDbEscapedString; 0036 0037 //! Internal MySQL connection data. 0038 /*! Provides a low-level API for accessing MySQL databases, that can 0039 be shared by any module that needs direct access to the underlying 0040 database. Used by the KDb and migration drivers. 0041 @todo fix the above note about migration... 0042 */ 0043 class MysqlConnectionInternal : public KDbConnectionInternal 0044 { 0045 public: 0046 explicit MysqlConnectionInternal(KDbConnection* connection); 0047 virtual ~MysqlConnectionInternal(); 0048 0049 //! Connects to a MySQL database 0050 /*! Connects to the MySQL server on host as the given user using the specified 0051 password. If host is "localhost", then a socket on the local file system 0052 can be specified to connect to the server (several defaults will be tried if 0053 none is specified). If the server is on a remote machine, then a port is 0054 the port that the remote server is listening on. 0055 */ 0056 bool db_connect(const KDbConnectionData& data); 0057 0058 //! Disconnects from the database 0059 bool db_disconnect(); 0060 0061 //! Selects a database that is about to be used 0062 bool useDatabase(const QString &dbName = QString()); 0063 0064 //! Executes query for a raw SQL statement @a sql using mysql_real_query() 0065 bool executeSql(const KDbEscapedString& sql); 0066 0067 static QString serverResultName(MYSQL *mysql); 0068 0069 void storeResult(KDbResult *result); 0070 0071 MYSQL *mysql; 0072 bool mysql_owned; //!< true if mysql pointer should be freed on destruction 0073 int res; //!< result code of last operation on server 0074 //! Get lower_case_table_name variable value so we know if there's case sensitivity supported for table and database names 0075 bool lowerCaseTableNames; 0076 //! Server version known after successfull connection. 0077 //! Equal to major_version*10000 + release_level*100 + sub_version 0078 //! 0 if not known. 0079 //! See https://dev.mysql.com/doc/refman/5.7/en/mysql-get-server-version.html 0080 //! @todo store in Connection base class as a property or as public server info 0081 unsigned long serverVersion; 0082 private: 0083 Q_DISABLE_COPY(MysqlConnectionInternal) 0084 }; 0085 0086 //! Internal MySQL cursor data. 0087 /*! Provides a low-level abstraction for iterating over MySql result sets. */ 0088 class MysqlCursorData : public MysqlConnectionInternal 0089 { 0090 public: 0091 explicit MysqlCursorData(KDbConnection* connection); 0092 ~MysqlCursorData() override; 0093 0094 MYSQL_RES *mysqlres; 0095 MYSQL_ROW mysqlrow; 0096 unsigned long *lengths; 0097 qint64 numRows; 0098 private: 0099 Q_DISABLE_COPY(MysqlCursorData) 0100 }; 0101 0102 class MysqlSqlField : public KDbSqlField 0103 { 0104 public: 0105 inline MysqlSqlField(MYSQL_FIELD *f) : data(f) { 0106 } 0107 //! @return column name 0108 inline QString name() override { 0109 //! @todo UTF8? 0110 return QString::fromLatin1(data->name); 0111 } 0112 inline int type() override { 0113 return data->type; 0114 } 0115 inline int length() override { 0116 return data->length; 0117 } 0118 MYSQL_FIELD *data; 0119 private: 0120 Q_DISABLE_COPY(MysqlSqlField) 0121 }; 0122 0123 class MysqlSqlRecord : public KDbSqlRecord 0124 { 0125 public: 0126 inline MysqlSqlRecord(MYSQL_ROW r, unsigned long* len) : record(r), lengths(len) { 0127 } 0128 inline ~MysqlSqlRecord() override { 0129 } 0130 inline QString stringValue(int index) override { 0131 return QString::fromUtf8(record[index], lengths[index]); 0132 } 0133 inline KDbSqlString cstringValue(int index) override { 0134 return KDbSqlString(record[index], lengths[index]); 0135 } 0136 inline QByteArray toByteArray(int index) override { 0137 return QByteArray(record[index], lengths[index]); 0138 } 0139 0140 private: 0141 MYSQL_ROW record; 0142 unsigned long* lengths; 0143 Q_DISABLE_COPY(MysqlSqlRecord) 0144 }; 0145 0146 class MysqlSqlResult : public KDbSqlResult 0147 { 0148 public: 0149 inline MysqlSqlResult(MysqlConnection *c, MYSQL_RES *d) 0150 : conn(c), data(d), fields(nullptr) 0151 { 0152 Q_ASSERT(c); 0153 } 0154 0155 inline ~MysqlSqlResult() override { 0156 if (data) { 0157 mysql_free_result(data); 0158 } 0159 } 0160 0161 inline KDbConnection *connection() const override { 0162 return conn; 0163 } 0164 0165 inline int fieldsCount() override { 0166 return data ? mysql_num_fields(data) : 0; 0167 } 0168 0169 Q_REQUIRED_RESULT inline KDbSqlField *field(int index) override { 0170 if (!fields) { 0171 if (!data) { 0172 return nullptr; 0173 } 0174 fields = mysql_fetch_fields(data); 0175 } 0176 return new MysqlSqlField(fields + index); 0177 } 0178 0179 Q_REQUIRED_RESULT KDbField *createField(const QString &tableName, int index) override; 0180 0181 Q_REQUIRED_RESULT inline QSharedPointer<KDbSqlRecord> fetchRecord() override 0182 { 0183 QSharedPointer<KDbSqlRecord> record; 0184 MYSQL_ROW row = data ? mysql_fetch_row(data) : nullptr; 0185 if (!row) { 0186 return record; 0187 } 0188 unsigned long* lengths = mysql_fetch_lengths(data); 0189 record.reset(new MysqlSqlRecord(row, lengths)); 0190 return record; 0191 } 0192 0193 inline KDbResult lastResult() override { 0194 KDbResult res; 0195 const int err = mysql_errno(conn->d->mysql); 0196 if (err != 0) { 0197 res.setCode(ERR_OTHER); 0198 res.setServerErrorCode(err); 0199 } 0200 return res; 0201 } 0202 0203 inline quint64 lastInsertRecordId() override { 0204 //! @todo 0205 return static_cast<quint64>(mysql_insert_id(conn->d->mysql)); 0206 } 0207 0208 private: 0209 //! @return a KDb type for MySQL type 0210 //! @todo prompt user if necessary? 0211 KDbField::Type type(const QString& tableName, MysqlSqlField *field); 0212 0213 //! @return a KDb BLOB-related type for MySQL type 0214 /*! Distinguishes between a BLOB and a TEXT types. 0215 MySQL uses the same field type to identify BLOB and TEXT fields. 0216 This method queries the server to find out if a field is a binary 0217 field or a text field. It also considers the length of CHAR and VARCHAR 0218 fields to see whether Text or LongText is the appropriate Kexi field type. 0219 Assumes fld is a CHAR, VARCHAR, one of the BLOBs or TEXTs. 0220 Returns KDbField::Text, KDbField::LongText or KDbField::BLOB. */ 0221 KDbField::Type blobType(const QString& tableName, MysqlSqlField *field); 0222 0223 MysqlConnection * const conn; 0224 MYSQL_RES * const data; 0225 MYSQL_FIELD *fields; 0226 Q_DISABLE_COPY(MysqlSqlResult) 0227 }; 0228 0229 #endif