diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/kexidb/drivers/mySQL | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/kexidb/drivers/mySQL')
-rw-r--r-- | kexi/kexidb/drivers/mySQL/Makefile.am | 33 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/kexidb_mysqldriver.desktop | 11 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mySQL.pro | 28 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlconnection.cpp | 208 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlconnection.h | 87 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlconnection_p.cpp | 175 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlconnection_p.h | 101 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlcursor.cpp | 218 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlcursor.h | 68 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqldriver.cpp | 212 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqldriver.h | 59 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlkeywords.cpp | 338 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.cpp | 298 | ||||
-rw-r--r-- | kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.h | 56 |
14 files changed, 1892 insertions, 0 deletions
diff --git a/kexi/kexidb/drivers/mySQL/Makefile.am b/kexi/kexidb/drivers/mySQL/Makefile.am new file mode 100644 index 00000000..dca6c26e --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/Makefile.am @@ -0,0 +1,33 @@ +include $(top_srcdir)/kexi/Makefile.global + +kde_module_LTLIBRARIES = kexidb_mysqldriver.la + +INCLUDES = -I$(MYSQL_INC) -I$(srcdir)/../../.. \ + -I$(srcdir)/../.. \ + -I$(top_srcdir)/kexi $(all_includes) + +kexidb_mysqldriver_la_METASOURCES = AUTO + +kexidb_mysqldriver_la_SOURCES = \ + mysqldriver.cpp \ + mysqlconnection.cpp \ + mysqlconnection_p.cpp \ + mysqlcursor.cpp \ + mysqlkeywords.cpp \ + mysqlpreparedstatement.cpp + +kexidb_mysqldriver_la_LIBADD = $(LIB_KPARTS) \ + $(LIB_QT) \ + $(MYSQL_LIBS) \ + -lmysqlclient \ + ../../libkexidb.la + +kexidb_mysqldriver_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(VER_INFO) -no-undefined + + +kde_services_DATA = kexidb_mysqldriver.desktop + + +KDE_CXXFLAGS += -DKEXIDB_MYSQL_DRIVER_EXPORT= -D__KEXIDB__= \ + -include $(top_srcdir)/kexi/kexidb/global.h + diff --git a/kexi/kexidb/drivers/mySQL/kexidb_mysqldriver.desktop b/kexi/kexidb/drivers/mySQL/kexidb_mysqldriver.desktop new file mode 100644 index 00000000..066782f1 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/kexidb_mysqldriver.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=MySQL +Name[ne]=मेरो एसक्यूएल +Name[sk]=mySQL +X-KDE-Library=kexidb_mysqldriver +ServiceTypes=Kexi/DBDriver +Type=Service +InitialPreference=8 +X-Kexi-DriverName=MySQL +X-Kexi-DriverType=Network +X-Kexi-KexiDBVersion=1.8 diff --git a/kexi/kexidb/drivers/mySQL/mySQL.pro b/kexi/kexidb/drivers/mySQL/mySQL.pro new file mode 100644 index 00000000..cc6eddd6 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mySQL.pro @@ -0,0 +1,28 @@ +include( ../common.pro ) + +INCLUDEPATH += $(MYSQL_INC) $(MYSQL_INC)/mysql + +contains(CONFIG,debug) { + win32:LIBS += $(MYSQL_LIB)/debug/libmysql.lib + win32:QMAKE_LFLAGS += /NODEFAULTLIB:LIBCMTD.LIB +} +!contains(CONFIG,debug) { +# win32:LIBS += $(MYSQL_LIB)/opt/mysqlclient.lib + win32:LIBS += $(MYSQL_LIB)/opt/libmysql.lib +# win32:QMAKE_LFLAGS += /NODEFAULTLIB:MSVCRT.LIB +} + +TARGET = kexidb_mysqldriver$$KDELIBDEBUG + +system( bash kmoc ) + +SOURCES = \ +mysqlconnection_p.cpp \ +mysqlconnection.cpp \ +mysqldriver.cpp \ +mysqlcursor.cpp \ +mysqlkeywords.cpp \ +mysqlpreparedstatement.cpp + +HEADERS = + diff --git a/kexi/kexidb/drivers/mySQL/mysqlconnection.cpp b/kexi/kexidb/drivers/mySQL/mysqlconnection.cpp new file mode 100644 index 00000000..7417b698 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlconnection.cpp @@ -0,0 +1,208 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at> + Daniel Molkentin <molkentin@kde.org> + Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org> + Copyright (C) 2004, 2006 Jaroslaw Staniek <js@iidea.pl> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qvariant.h> +#include <qfile.h> +#include <qdict.h> +#include <qregexp.h> + +#include <kgenericfactory.h> +#include <kdebug.h> + +#include "mysqldriver.h" +#include "mysqlconnection.h" +#include "mysqlconnection_p.h" +#include "mysqlcursor.h" +#include "mysqlpreparedstatement.h" +#include <kexidb/error.h> + + +using namespace KexiDB; + +//-------------------------------------------------------------------------- + +MySqlConnection::MySqlConnection( Driver *driver, ConnectionData &conn_data ) + :Connection(driver,conn_data) + ,d(new MySqlConnectionInternal(this)) +{ +} + +MySqlConnection::~MySqlConnection() { + destroy(); +} + +bool MySqlConnection::drv_connect(KexiDB::ServerVersionInfo& version) +{ + const bool ok = d->db_connect(*data()); + if (!ok) + return false; + + version.string = mysql_get_host_info(d->mysql); + + //retrieve server version info +#if 0 //this only works for client version >= 4.1 :( + unsigned long v = mysql_get_server_version(d->mysql); + // v - a number that represents the MySQL server version in this format + // = major_version*10000 + minor_version *100 + sub_version + version.major = v/10000; + version.minor = (v - version.major*10000)/100; + version.release = v - version.major*10000 - version.minor*100; +#else //better way to get the version info: use 'version' built-in variable: +//! @todo this is hardcoded for now; define api for retrieving variables and use this API... + QString versionString; + const tristate res = querySingleString("SELECT @@version", versionString, /*column*/0, false /*!addLimitTo1*/); + QRegExp versionRe("(\\d+)\\.(\\d+)\\.(\\d+)"); + if (res==true && versionRe.exactMatch(versionString)) { // (if querySingleString failed, the version will be 0.0.0... + version.major = versionRe.cap(1).toInt(); + version.minor = versionRe.cap(2).toInt(); + version.release = versionRe.cap(3).toInt(); + } +#endif + return true; +} + +bool MySqlConnection::drv_disconnect() { + return d->db_disconnect(); +} + +Cursor* MySqlConnection::prepareQuery(const QString& statement, uint cursor_options) { + return new MySqlCursor(this,statement,cursor_options); +} + +Cursor* MySqlConnection::prepareQuery( QuerySchema& query, uint cursor_options ) { + return new MySqlCursor( this, query, cursor_options ); +} + +bool MySqlConnection::drv_getDatabasesList( QStringList &list ) { + KexiDBDrvDbg << "MySqlConnection::drv_getDatabasesList()" << endl; + list.clear(); + MYSQL_RES *res; + + if((res=mysql_list_dbs(d->mysql,0)) != 0) { + MYSQL_ROW row; + while ( (row = mysql_fetch_row(res))!=0) { + list<<QString(row[0]); + } + mysql_free_result(res); + return true; + } + + d->storeResult(); +// setError(ERR_DB_SPECIFIC,mysql_error(d->mysql)); + return false; +} + +bool MySqlConnection::drv_createDatabase( const QString &dbName) { + KexiDBDrvDbg << "MySqlConnection::drv_createDatabase: " << dbName << endl; + // mysql_create_db deprecated, use SQL here. + if (drv_executeSQL("CREATE DATABASE " + (dbName))) + return true; + d->storeResult(); + return false; +} + +bool MySqlConnection::drv_useDatabase(const QString &dbName, bool *cancelled, MessageHandler* msgHandler) +{ + Q_UNUSED(cancelled); + Q_UNUSED(msgHandler); +//TODO is here escaping needed? + return d->useDatabase(dbName); +} + +bool MySqlConnection::drv_closeDatabase() { +//TODO free resources +//As far as I know, mysql doesn't support that + return true; +} + +bool MySqlConnection::drv_dropDatabase( const QString &dbName) { +//TODO is here escaping needed + return drv_executeSQL("drop database "+dbName); +} + +bool MySqlConnection::drv_executeSQL( const QString& statement ) { + return d->executeSQL(statement); +} + +Q_ULLONG MySqlConnection::drv_lastInsertRowID() +{ + //! @todo + return (Q_ULLONG)mysql_insert_id(d->mysql); +} + +int MySqlConnection::serverResult() +{ + return d->res; +} + +QString MySqlConnection::serverResultName() +{ + return QString::null; +} + +void MySqlConnection::drv_clearServerResult() +{ + if (!d) + return; + d->res = 0; +} + +QString MySqlConnection::serverErrorMsg() +{ + return d->errmsg; +} + +bool MySqlConnection::drv_containsTable( const QString &tableName ) +{ + bool success; + return resultExists(QString("show tables like %1") + .arg(driver()->escapeString(tableName)), success) && success; +} + +bool MySqlConnection::drv_getTablesList( QStringList &list ) +{ + KexiDB::Cursor *cursor; + m_sql = "show tables"; + if (!(cursor = executeQuery( m_sql ))) { + KexiDBDbg << "Connection::drv_getTablesList(): !executeQuery()" << endl; + return false; + } + list.clear(); + cursor->moveFirst(); + while (!cursor->eof() && !cursor->error()) { + list += cursor->value(0).toString(); + cursor->moveNext(); + } + if (cursor->error()) { + deleteCursor(cursor); + return false; + } + return deleteCursor(cursor); +} + +PreparedStatement::Ptr MySqlConnection::prepareStatement(PreparedStatement::StatementType type, + FieldList& fields) +{ + return new MySqlPreparedStatement(type, *d, fields); +} + +#include "mysqlconnection.moc" diff --git a/kexi/kexidb/drivers/mySQL/mysqlconnection.h b/kexi/kexidb/drivers/mySQL/mysqlconnection.h new file mode 100644 index 00000000..bafb889d --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlconnection.h @@ -0,0 +1,87 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at> + Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org> + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef MYSQLCONNECTION_H +#define MYSQLCONNECTION_H + +#include <qstringlist.h> + +#include <kexidb/connection.h> +#include "mysqlcursor.h" +#include <qdict.h> + +namespace KexiDB { + +class MySqlConnectionInternal; + +/*! + * Should override kexiDB/kexiDB + * all other members are done by the + * base class. + */ +class MySqlConnection : public Connection +{ + Q_OBJECT + + public: + virtual ~MySqlConnection(); + + virtual Cursor* prepareQuery( const QString& statement = QString::null, uint cursor_options = 0 ); + virtual Cursor* prepareQuery( QuerySchema& query, uint cursor_options = 0 ); + + virtual PreparedStatement::Ptr prepareStatement(PreparedStatement::StatementType type, + FieldList& fields); + + protected: + + /*! Used by driver */ + MySqlConnection( Driver *driver, ConnectionData &conn_data ); + + virtual bool drv_connect(KexiDB::ServerVersionInfo& version); + virtual bool drv_disconnect(); + virtual bool drv_getDatabasesList( QStringList &list ); + virtual bool drv_createDatabase( const QString &dbName = QString::null ); + virtual bool drv_useDatabase( const QString &dbName = QString::null, bool *cancelled = 0, + MessageHandler* msgHandler = 0 ); + virtual bool drv_closeDatabase(); + virtual bool drv_dropDatabase( const QString &dbName = QString::null ); + virtual bool drv_executeSQL( const QString& statement ); + virtual Q_ULLONG drv_lastInsertRowID(); + + virtual int serverResult(); + virtual QString serverResultName(); + virtual QString serverErrorMsg(); + virtual void drv_clearServerResult(); + +//TODO: move this somewhere to low level class (MIGRATION?) + virtual bool drv_getTablesList( QStringList &list ); +//TODO: move this somewhere to low level class (MIGRATION?) + virtual bool drv_containsTable( const QString &tableName ); + + MySqlConnectionInternal* d; + + friend class MySqlDriver; + friend class MySqlCursor; +}; + +} + +#endif diff --git a/kexi/kexidb/drivers/mySQL/mysqlconnection_p.cpp b/kexi/kexidb/drivers/mySQL/mysqlconnection_p.cpp new file mode 100644 index 00000000..9797ca96 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlconnection_p.cpp @@ -0,0 +1,175 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl> + Copyright (C) 2004 Martin Ellis <martin.ellis@kdemail.net> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcstring.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qfile.h> + +#include <kdebug.h> + +#include "mysqlconnection_p.h" + +#include <kexidb/connectiondata.h> + +#ifdef MYSQLMIGRATE_H +#define NAMESPACE KexiMigration +#else +#define NAMESPACE KexiDB +#endif + +using namespace NAMESPACE; + +/* ************************************************************************** */ +MySqlConnectionInternal::MySqlConnectionInternal(KexiDB::Connection* connection) + : ConnectionInternal(connection) + , mysql(0) + , mysql_owned(true) + , res(0) +{ +} + +MySqlConnectionInternal::~MySqlConnectionInternal() +{ + if (mysql_owned && mysql) { + mysql_close(mysql); + mysql = 0; + } +} + +void MySqlConnectionInternal::storeResult() +{ + res = mysql_errno(mysql); + errmsg = mysql_error(mysql); +} + +/* ************************************************************************** */ +/*! Connects to the MySQL server on host as the given user using the specified + password. If host is "localhost", then a socket on the local file system + can be specified to connect to the server (several defaults will be tried if + none is specified). If the server is on a remote machine, then a port is + the port that the remote server is listening on. + */ +//bool MySqlConnectionInternal::db_connect(QCString host, QCString user, +// QCString password, unsigned short int port, QString socket) +bool MySqlConnectionInternal::db_connect(const KexiDB::ConnectionData& data) +{ + if (!(mysql = mysql_init(mysql))) + return false; + + KexiDBDrvDbg << "MySqlConnectionInternal::connect()" << endl; + QCString localSocket; + QString hostName = data.hostName; + if (hostName.isEmpty() || hostName.lower()=="localhost") { + if (data.useLocalSocketFile) { + if (data.localSocketFileName.isEmpty()) { + //! @todo move the list of default sockets to a generic method + QStringList sockets; + #ifndef Q_WS_WIN + sockets.append("/var/lib/mysql/mysql.sock"); + sockets.append("/var/run/mysqld/mysqld.sock"); + sockets.append("/tmp/mysql.sock"); + + for(QStringList::ConstIterator it = sockets.constBegin(); it != sockets.constEnd(); it++) + { + if(QFile(*it).exists()) { + localSocket = ((QString)(*it)).local8Bit(); + break; + } + } + #endif + } + else + localSocket = QFile::encodeName(data.localSocketFileName); + } + else { + //we're not using local socket + hostName = "127.0.0.1"; //this will force mysql to connect to localhost + } + } + +/*! @todo is latin1() encoding here valid? what about using UTF for passwords? */ + const char *pwd = data.password.isNull() ? 0 : data.password.latin1(); + mysql_real_connect(mysql, hostName.latin1(), data.userName.latin1(), + pwd, 0, data.port, localSocket, 0); + if(mysql_errno(mysql) == 0) + return true; + + storeResult(); //store error msg, if any - can be destroyed after disconnect() + db_disconnect(); +// setError(ERR_DB_SPECIFIC,err); + return false; +} + +/*! Disconnects from the database. + */ +bool MySqlConnectionInternal::db_disconnect() +{ + mysql_close(mysql); + mysql = 0; + KexiDBDrvDbg << "MySqlConnection::disconnect()" << endl; + return true; +} + +/* ************************************************************************** */ +/*! Selects dbName as the active database so it can be used. + */ +bool MySqlConnectionInternal::useDatabase(const QString &dbName) { +//TODO is here escaping needed? + return executeSQL("USE " + dbName); +} + +/*! Executes the given SQL statement on the server. + */ +bool MySqlConnectionInternal::executeSQL(const QString& statement) { +// KexiDBDrvDbg << "MySqlConnectionInternal::executeSQL: " +// << statement << endl; + QCString queryStr=statement.utf8(); + const char *query=queryStr; + if(mysql_real_query(mysql, query, strlen(query)) == 0) + { + return true; + } + + storeResult(); +// setError(ERR_DB_SPECIFIC,mysql_error(m_mysql)); + return false; +} + +QString MySqlConnectionInternal::escapeIdentifier(const QString& str) const { + return QString(str).replace('`', "'"); +} + +//-------------------------------------- + +MySqlCursorData::MySqlCursorData(KexiDB::Connection* connection) +: MySqlConnectionInternal(connection) +, mysqlres(0) +, mysqlrow(0) +, lengths(0) +, numRows(0) +{ + mysql_owned = false; +} + +MySqlCursorData::~MySqlCursorData() +{ +} + diff --git a/kexi/kexidb/drivers/mySQL/mysqlconnection_p.h b/kexi/kexidb/drivers/mySQL/mysqlconnection_p.h new file mode 100644 index 00000000..5bb77487 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlconnection_p.h @@ -0,0 +1,101 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Martin Ellis <martin.ellis@kdemail.net> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXIDB_MYSQLCLIENT_P_H +#define KEXIDB_MYSQLCLIENT_P_H + +#include <kexidb/connection_p.h> + +#ifdef Q_WS_WIN +#include <my_global.h> +#endif +#include <mysql_version.h> +#include <mysql.h> + +typedef struct st_mysql MYSQL; +#undef bool + +class QCString; +class QString; + +#ifdef MYSQLMIGRATE_H +#define NAMESPACE KexiMigration +#else +#define NAMESPACE KexiDB +#endif + +namespace KexiDB { + class ConnectionData; +} + +namespace NAMESPACE { + +//! Internal MySQL connection data. +/*! Provides a low-level API for accessing MySQL databases, that can + be shared by any module that needs direct access to the underlying + database. Used by the KexiDB and KexiMigration drivers. + */ +class MySqlConnectionInternal : public KexiDB::ConnectionInternal +{ + public: + MySqlConnectionInternal(KexiDB::Connection* connection); + virtual ~MySqlConnectionInternal(); + + //! Connects to a MySQL database + bool db_connect(const KexiDB::ConnectionData& data); + + //! Disconnects from the database + bool db_disconnect(); + + //! Selects a database that is about to be used + bool useDatabase(const QString &dbName = QString::null); + + //! Execute SQL statement on the database + bool executeSQL( const QString& statement ); + + //! Stores last operation's result + virtual void storeResult(); + + //! Escapes a table, database or column name + QString escapeIdentifier(const QString& str) const; + + MYSQL *mysql; + bool mysql_owned; //!< true if mysql pointer should be freed on destruction + QString errmsg; //!< server-specific message of last operation + int res; //!< result code of last operation on server +}; + + +//! Internal MySQL cursor data. +/*! Provides a low-level abstraction for iterating over MySql result sets. */ +class MySqlCursorData : public MySqlConnectionInternal +{ + public: + MySqlCursorData(KexiDB::Connection* connection); + virtual ~MySqlCursorData(); + + MYSQL_RES *mysqlres; + MYSQL_ROW mysqlrow; + unsigned long *lengths; + unsigned long numRows; +}; + +} + +#endif diff --git a/kexi/kexidb/drivers/mySQL/mysqlcursor.cpp b/kexi/kexidb/drivers/mySQL/mysqlcursor.cpp new file mode 100644 index 00000000..7897fa97 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlcursor.cpp @@ -0,0 +1,218 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org> + Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "mysqlcursor.h" +#include "mysqlconnection.h" +#include "mysqlconnection_p.h" +#include <kexidb/error.h> +#include <kexidb/utils.h> +#include <klocale.h> +#include <kdebug.h> +#include <limits.h> + +#define BOOL bool + +using namespace KexiDB; + +MySqlCursor::MySqlCursor(KexiDB::Connection* conn, const QString& statement, uint cursor_options) + : Cursor(conn,statement,cursor_options) + , d( new MySqlCursorData(conn) ) +{ + m_options |= Buffered; + d->mysql = static_cast<MySqlConnection*>(conn)->d->mysql; +// KexiDBDrvDbg << "MySqlCursor: constructor for query statement" << endl; +} + +MySqlCursor::MySqlCursor(Connection* conn, QuerySchema& query, uint options ) + : Cursor( conn, query, options ) + , d( new MySqlCursorData(conn) ) +{ + m_options |= Buffered; + d->mysql = static_cast<MySqlConnection*>(conn)->d->mysql; +// KexiDBDrvDbg << "MySqlCursor: constructor for query statement" << endl; +} + +MySqlCursor::~MySqlCursor() { + close(); +} + +bool MySqlCursor::drv_open() { +// KexiDBDrvDbg << "MySqlCursor::drv_open:" << m_sql << endl; + // This can't be right? mysql_real_query takes a length in order that + // queries can have binary data - but strlen does not allow binary data. + if(mysql_real_query(d->mysql, m_sql.utf8(), strlen(m_sql.utf8())) == 0) { + if(mysql_errno(d->mysql) == 0) { + d->mysqlres= mysql_store_result(d->mysql); + m_fieldCount=mysql_num_fields(d->mysqlres); + d->numRows=mysql_num_rows(d->mysqlres); + m_at=0; + + m_opened=true; + m_records_in_buf = d->numRows; + m_buffering_completed = true; + m_afterLast=false; + return true; + } + } + + setError(ERR_DB_SPECIFIC,QString::fromUtf8(mysql_error(d->mysql))); + return false; +} + +bool MySqlCursor::drv_close() { + mysql_free_result(d->mysqlres); + d->mysqlres=0; + d->mysqlrow=0; +//js: done in superclass: m_numFields=0; + d->lengths=0; + m_opened=false; + d->numRows=0; + return true; +} + +/*bool MySqlCursor::drv_moveFirst() { + return true; //TODO +}*/ + +void MySqlCursor::drv_getNextRecord() { +// KexiDBDrvDbg << "MySqlCursor::drv_getNextRecord" << endl; + if (at() < d->numRows && at() >=0) { + d->lengths=mysql_fetch_lengths(d->mysqlres); + m_result=FetchOK; + } + else if (at() >= d->numRows) { + m_result = FetchEnd; + } + else { + m_result = FetchError; + } +} + +// This isn't going to work right now as it uses d->mysqlrow +QVariant MySqlCursor::value(uint pos) { + if (!d->mysqlrow || pos>=m_fieldCount || d->mysqlrow[pos]==0) + return QVariant(); + + KexiDB::Field *f = (m_fieldsExpanded && pos<m_fieldsExpanded->count()) + ? m_fieldsExpanded->at(pos)->field : 0; + +//! @todo js: use MYSQL_FIELD::type here! + + return KexiDB::cstringToVariant(d->mysqlrow[pos], f, d->lengths[pos]); +/* moved to cstringToVariant() + //from most to least frequently used types: + if (!f || f->isTextType()) + return QVariant( QString::fromUtf8((const char*)d->mysqlrow[pos], d->lengths[pos]) ); + else if (f->isIntegerType()) +//! @todo support BigInteger + return QVariant( QCString((const char*)d->mysqlrow[pos], d->lengths[pos]).toInt() ); + else if (f->isFPNumericType()) + return QVariant( QCString((const char*)d->mysqlrow[pos], d->lengths[pos]).toDouble() ); + + //default + return QVariant(QString::fromUtf8((const char*)d->mysqlrow[pos], d->lengths[pos]));*/ +} + + +/* As with sqlite, the DB library returns all values (including numbers) as + strings. So just put that string in a QVariant and let KexiDB deal with it. + */ +void MySqlCursor::storeCurrentRow(RowData &data) const +{ +// KexiDBDrvDbg << "MySqlCursor::storeCurrentRow: Position is " << (long)m_at<< endl; + if (d->numRows<=0) + return; + +//! @todo js: use MYSQL_FIELD::type here! +//! see SQLiteCursor::storeCurrentRow() + + data.resize(m_fieldCount); + const uint fieldsExpandedCount = m_fieldsExpanded ? m_fieldsExpanded->count() : UINT_MAX; + const uint realCount = QMIN(fieldsExpandedCount, m_fieldCount); + for( uint i=0; i<realCount; i++) { + Field *f = m_fieldsExpanded ? m_fieldsExpanded->at(i)->field : 0; + if (m_fieldsExpanded && !f) + continue; + data[i] = KexiDB::cstringToVariant(d->mysqlrow[i], f, d->lengths[i]); +/* moved to cstringToVariant() + if (f && f->type()==Field::BLOB) { + QByteArray ba; + ba.duplicate(d->mysqlrow[i], d->lengths[i]); + data[i] = ba; + KexiDBDbg << data[i].toByteArray().size() << endl; + } +//! @todo more types! +//! @todo look at what type mysql declares! + else { + data[i] = QVariant(QString::fromUtf8((const char*)d->mysqlrow[i], d->lengths[i])); + }*/ + } +} + +void MySqlCursor::drv_appendCurrentRecordToBuffer() { +} + + +void MySqlCursor::drv_bufferMovePointerNext() { + d->mysqlrow=mysql_fetch_row(d->mysqlres); + d->lengths=mysql_fetch_lengths(d->mysqlres); +} + +void MySqlCursor::drv_bufferMovePointerPrev() { + //MYSQL_ROW_OFFSET ro=mysql_row_tell(d->mysqlres); + mysql_data_seek(d->mysqlres,m_at-1); + d->mysqlrow=mysql_fetch_row(d->mysqlres); + d->lengths=mysql_fetch_lengths(d->mysqlres); +} + + +void MySqlCursor::drv_bufferMovePointerTo(Q_LLONG to) { + //MYSQL_ROW_OFFSET ro=mysql_row_tell(d->mysqlres); + mysql_data_seek(d->mysqlres, to); + d->mysqlrow=mysql_fetch_row(d->mysqlres); + d->lengths=mysql_fetch_lengths(d->mysqlres); +} + +const char** MySqlCursor::rowData() const { + //! @todo + return 0; +} + +int MySqlCursor::serverResult() +{ + return d->res; +} + +QString MySqlCursor::serverResultName() +{ + return QString::null; +} + +void MySqlCursor::drv_clearServerResult() +{ + if (!d) + return; + d->res = 0; +} + +QString MySqlCursor::serverErrorMsg() +{ + return d->errmsg; +} diff --git a/kexi/kexidb/drivers/mySQL/mysqlcursor.h b/kexi/kexidb/drivers/mySQL/mysqlcursor.h new file mode 100644 index 00000000..09ace22b --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlcursor.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project +Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef _MYSQLCURSOR_H_ +#define _MYSQLCURSOR_H_ + +#include <kexidb/cursor.h> +#include <kexidb/connection.h> + +namespace KexiDB { + +class MySqlCursorData; + +class MySqlCursor: public Cursor { +public: + MySqlCursor(Connection* conn, const QString& statement = QString::null, uint cursor_options = NoOptions ); + MySqlCursor(Connection* conn, QuerySchema& query, uint options = NoOptions ); + virtual ~MySqlCursor(); + virtual bool drv_open(); + virtual bool drv_close(); +// virtual bool drv_moveFirst(); + virtual void drv_getNextRecord(); + //virtual bool drv_getPrevRecord(); + virtual QVariant value(uint); + + virtual void drv_clearServerResult(); + virtual void drv_appendCurrentRecordToBuffer(); + virtual void drv_bufferMovePointerNext(); + virtual void drv_bufferMovePointerPrev(); + virtual void drv_bufferMovePointerTo(Q_LLONG to); + virtual const char** rowData() const; + virtual void storeCurrentRow(RowData &data) const; +// virtual bool save(RowData& data, RowEditBuffer& buf); + + virtual int serverResult(); + virtual QString serverResultName(); + virtual QString serverErrorMsg(); + +protected: + QVariant pValue(uint pos) const; +// MYSQL_RES *m_res; +// MYSQL_ROW m_row; +// MYSQL *my_conn; +// unsigned long *m_lengths; +//js: int m_numFields; +// unsigned long m_numRows; + MySqlCursorData *d; +}; + +} + +#endif diff --git a/kexi/kexidb/drivers/mySQL/mysqldriver.cpp b/kexi/kexidb/drivers/mySQL/mysqldriver.cpp new file mode 100644 index 00000000..c27681c0 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqldriver.cpp @@ -0,0 +1,212 @@ +/* This file is part of the KDE project +Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at> +Daniel Molkentin <molkentin@kde.org> +Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifdef Q_WS_WIN +# include <mysql/config-win.h> +#endif +#include <mysql_version.h> +#include <mysql.h> +#define BOOL bool + +#include <qvariant.h> +#include <qfile.h> +#include <qdict.h> + +#include <kgenericfactory.h> +#include <kdebug.h> + +#include "mysqldriver.h" +#include "mysqlconnection.h" +#include <kexidb/field.h> +#include <kexidb/driver_p.h> +#include <kexidb/utils.h> + +using namespace KexiDB; + +KEXIDB_DRIVER_INFO( MySqlDriver, mysql ) + +/* TODO: Implement buffered/unbuffered, rather than buffer everything. + Each MYSQL connection can only handle at most one unbuffered cursor, + so MySqlConnection should keep count? + */ + +/*! + * Constructor sets database features and + * maps the types in KexiDB::Field::Type to the MySQL types. + * + * See: http://dev.mysql.com/doc/mysql/en/Column_types.html + */ +MySqlDriver::MySqlDriver(QObject *parent, const char *name, const QStringList &args) : Driver(parent, name,args) +{ +// KexiDBDrvDbg << "MySqlDriver::MySqlDriver()" << endl; + + d->isFileDriver=false; + d->features=IgnoreTransactions | CursorForward; + + beh->ROW_ID_FIELD_NAME="LAST_INSERT_ID()"; + beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE=true; + beh->_1ST_ROW_READ_AHEAD_REQUIRED_TO_KNOW_IF_THE_RESULT_IS_EMPTY=false; + beh->USING_DATABASE_REQUIRED_TO_CONNECT=false; + beh->QUOTATION_MARKS_FOR_IDENTIFIER='`'; + beh->SQL_KEYWORDS = keywords; + initSQLKeywords(331); + + //predefined properties +#if MYSQL_VERSION_ID < 40000 + d->properties["client_library_version"] = MYSQL_SERVER_VERSION; //nothing better + d->properties["default_server_encoding"] = MYSQL_CHARSET; //nothing better +#elif MYSQL_VERSION_ID < 50000 +//OK? d->properties["client_library_version"] = mysql_get_client_version(); +#endif + + d->typeNames[Field::Byte]="TINYINT"; + d->typeNames[Field::ShortInteger]="SMALLINT"; + d->typeNames[Field::Integer]="INT"; + d->typeNames[Field::BigInteger]="BIGINT"; + // Can use BOOLEAN here, but BOOL has been in MySQL longer + d->typeNames[Field::Boolean]="BOOL"; + d->typeNames[Field::Date]="DATE"; + d->typeNames[Field::DateTime]="DATETIME"; + d->typeNames[Field::Time]="TIME"; + d->typeNames[Field::Float]="FLOAT"; + d->typeNames[Field::Double]="DOUBLE"; + d->typeNames[Field::Text]="VARCHAR"; + d->typeNames[Field::LongText]="LONGTEXT"; + d->typeNames[Field::BLOB]="BLOB"; +} + +MySqlDriver::~MySqlDriver() +{ +} + +KexiDB::Connection* +MySqlDriver::drv_createConnection( ConnectionData &conn_data ) +{ + return new MySqlConnection( this, conn_data ); +} + +bool MySqlDriver::isSystemDatabaseName(const QString &n) const +{ + return n.lower()=="mysql" || Driver::isSystemObjectName(n); +} + +bool MySqlDriver::drv_isSystemFieldName(const QString&) const { + return false; +} + +QString MySqlDriver::escapeString(const QString& str) const +{ + //escape as in http://dev.mysql.com/doc/refman/5.0/en/string-syntax.html +//! @todo support more characters, like %, _ + + const int old_length = str.length(); + int i; + for ( i = 0; i < old_length; i++ ) { //anything to escape? + const unsigned int ch = str[i].unicode(); + if (ch == '\\' || ch == '\'' || ch == '"' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\b' || ch == '\0') + break; + } + if (i >= old_length) { //no characters to escape + return QString::fromLatin1("'") + str + QString::fromLatin1("'"); + } + + QChar *new_string = new QChar[ old_length * 3 + 1 ]; // a worst case approximation +//! @todo move new_string to Driver::m_new_string or so... + int new_length = 0; + new_string[new_length++] = '\''; //prepend ' + for ( i = 0; i < old_length; i++, new_length++ ) { + const unsigned int ch = str[i].unicode(); + if (ch == '\\') { + new_string[new_length++] = '\\'; + new_string[new_length] = '\\'; + } + else if (ch <= '\'') {//check for speedup + if (ch == '\'') { + new_string[new_length++] = '\\'; + new_string[new_length] = '\''; + } + else if (ch == '"') { + new_string[new_length++] = '\\'; + new_string[new_length] = '"'; + } + else if (ch == '\n') { + new_string[new_length++] = '\\'; + new_string[new_length] = 'n'; + } + else if (ch == '\r') { + new_string[new_length++] = '\\'; + new_string[new_length] = 'r'; + } + else if (ch == '\t') { + new_string[new_length++] = '\\'; + new_string[new_length] = 't'; + } + else if (ch == '\b') { + new_string[new_length++] = '\\'; + new_string[new_length] = 'b'; + } + else if (ch == '\0') { + new_string[new_length++] = '\\'; + new_string[new_length] = '0'; + } + else + new_string[new_length] = str[i]; + } + else + new_string[new_length] = str[i]; + } + + new_string[new_length++] = '\''; //append ' + QString result(new_string, new_length); + delete [] new_string; + return result; +} + +QString MySqlDriver::escapeBLOB(const QByteArray& array) const +{ + return KexiDB::escapeBLOB(array, KexiDB::BLOBEscape0xHex); +} + +QCString MySqlDriver::escapeString(const QCString& str) const +{ +//! @todo optimize using mysql_real_escape_string()? +//! see http://dev.mysql.com/doc/refman/5.0/en/string-syntax.html + + return QCString("'")+QCString(str) + .replace( '\\', "\\\\" ) + .replace( '\'', "\\''" ) + .replace( '"', "\\\"" ) + + QCString("'"); +} + +/*! Add back-ticks to an identifier, and replace any back-ticks within + * the name with single quotes. + */ +QString MySqlDriver::drv_escapeIdentifier( const QString& str) const { + return QString(str).replace('`', "'"); +} + +QCString MySqlDriver::drv_escapeIdentifier( const QCString& str) const { + return QCString(str).replace('`', "'"); +} + +#include "mysqldriver.moc" + diff --git a/kexi/kexidb/drivers/mySQL/mysqldriver.h b/kexi/kexidb/drivers/mySQL/mysqldriver.h new file mode 100644 index 00000000..8282e215 --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqldriver.h @@ -0,0 +1,59 @@ +/* This file is part of the KDE project +Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at> +Daniel Molkentin <molkentin@kde.org> +Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef MYSQLDB_H +#define MYSQLDB_H + +#include <kexidb/driver.h> + +namespace KexiDB { + +//! MySQL database driver. +class MySqlDriver : public Driver +{ + Q_OBJECT + KEXIDB_DRIVER + + public: + MySqlDriver(QObject *parent, const char *name, const QStringList &args=QStringList()); + virtual ~MySqlDriver(); + + virtual bool isSystemDatabaseName( const QString &n ) const; + + //! Escape a string for use as a value + virtual QString escapeString(const QString& str) const; + virtual QCString escapeString(const QCString& str) const; + + //! Escape BLOB value \a array + virtual QString escapeBLOB(const QByteArray& array) const; + + protected: + virtual QString drv_escapeIdentifier( const QString& str) const; + virtual QCString drv_escapeIdentifier( const QCString& str) const; + virtual Connection *drv_createConnection( ConnectionData &conn_data ); + virtual bool drv_isSystemFieldName( const QString& n ) const; + + private: + static const char *keywords[]; +}; +} + +#endif diff --git a/kexi/kexidb/drivers/mySQL/mysqlkeywords.cpp b/kexi/kexidb/drivers/mySQL/mysqlkeywords.cpp new file mode 100644 index 00000000..e06adb5e --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlkeywords.cpp @@ -0,0 +1,338 @@ + /* + * This file has been automatically generated from + * koffice/kexi/tools/sql_keywords/sql_keywords.sh and + * mysql-4.1.7/sql/lex.h. + * + * Please edit the sql_keywords.sh, not this file! + */ +#include <mysqldriver.h> + +namespace KexiDB { + const char* MySqlDriver::keywords[] = { + "ACTION", + "ADD", + "AGAINST", + "AGGREGATE", + "ALTER", + "ANALYZE", + "ANY", + "ASCII", + "AUTO_INCREMENT", + "AVG", + "AVG_ROW_LENGTH", + "BACKUP", + "BDB", + "BERKELEYDB", + "BIGINT", + "BINARY", + "BINLOG", + "BIT", + "BLOB", + "BOOL", + "BOOLEAN", + "BOTH", + "BTREE", + "BYTE", + "CACHE", + "CHANGE", + "CHANGED", + "CHAR", + "CHARACTER", + "CHARSET", + "CHECKSUM", + "CIPHER", + "CLIENT", + "CLOSE", + "COLLATION", + "COLUMN", + "COLUMNS", + "COMMENT", + "COMMITTED", + "COMPRESSED", + "CONCURRENT", + "CONVERT", + "CUBE", + "CURRENT_DATE", + "CURRENT_TIME", + "CURRENT_TIMESTAMP", + "CURRENT_USER", + "DATA", + "DATABASES", + "DATE", + "DATETIME", + "DAY", + "DAY_HOUR", + "DAY_MICROSECOND", + "DAY_MINUTE", + "DAY_SECOND", + "DEALLOCATE", + "DEC", + "DECIMAL", + "DELAYED", + "DELAY_KEY_WRITE", + "DESCRIBE", + "DES_KEY_FILE", + "DIRECTORY", + "DISABLE", + "DISCARD", + "DISTINCTROW", + "DIV", + "DO", + "DOUBLE", + "DUAL", + "DUMPFILE", + "DUPLICATE", + "DYNAMIC", + "ENABLE", + "ENCLOSED", + "ENGINE", + "ENGINES", + "ENUM", + "ERRORS", + "ESCAPE", + "ESCAPED", + "EVENTS", + "EXECUTE", + "EXISTS", + "EXPANSION", + "EXTENDED", + "FALSE", + "FAST", + "FIELDS", + "FILE", + "FIRST", + "FIXED", + "FLOAT", + "FLOAT4", + "FLOAT8", + "FLUSH", + "FORCE", + "FULLTEXT", + "FUNCTION", + "GEOMETRY", + "GEOMETRYCOLLECTION", + "GET_FORMAT", + "GLOBAL", + "GRANT", + "GRANTS", + "HANDLER", + "HASH", + "HELP", + "HIGH_PRIORITY", + "HOSTS", + "HOUR", + "HOUR_MICROSECOND", + "HOUR_MINUTE", + "HOUR_SECOND", + "IDENTIFIED", + "IF", + "IMPORT", + "INDEXES", + "INFILE", + "INNOBASE", + "INNODB", + "INSERT_METHOD", + "INT", + "INT1", + "INT2", + "INT3", + "INT4", + "INT8", + "INTERVAL", + "IO_THREAD", + "ISOLATION", + "ISSUER", + "KEYS", + "KILL", + "LAST", + "LEADING", + "LEAVES", + "LEVEL", + "LINES", + "LINESTRING", + "LOAD", + "LOCAL", + "LOCALTIME", + "LOCALTIMESTAMP", + "LOCK", + "LOCKS", + "LOGS", + "LONG", + "LONGBLOB", + "LONGTEXT", + "LOW_PRIORITY", + "MASTER", + "MASTER_CONNECT_RETRY", + "MASTER_HOST", + "MASTER_LOG_FILE", + "MASTER_LOG_POS", + "MASTER_PASSWORD", + "MASTER_PORT", + "MASTER_SERVER_ID", + "MASTER_SSL", + "MASTER_SSL_CA", + "MASTER_SSL_CAPATH", + "MASTER_SSL_CERT", + "MASTER_SSL_CIPHER", + "MASTER_SSL_KEY", + "MASTER_USER", + "MAX_CONNECTIONS_PER_HOUR", + "MAX_QUERIES_PER_HOUR", + "MAX_ROWS", + "MAX_UPDATES_PER_HOUR", + "MEDIUM", + "MEDIUMBLOB", + "MEDIUMINT", + "MEDIUMTEXT", + "MICROSECOND", + "MIDDLEINT", + "MINUTE", + "MINUTE_MICROSECOND", + "MINUTE_SECOND", + "MIN_ROWS", + "MOD", + "MODE", + "MODIFY", + "MONTH", + "MULTILINESTRING", + "MULTIPOINT", + "MULTIPOLYGON", + "NAMES", + "NATIONAL", + "NDB", + "NDBCLUSTER", + "NCHAR", + "NEW", + "NEXT", + "NO", + "NONE", + "NO_WRITE_TO_BINLOG", + "NUMERIC", + "NVARCHAR", + "OLD_PASSWORD", + "ONE_SHOT", + "OPEN", + "OPTIMIZE", + "OPTION", + "OPTIONALLY", + "OUTFILE", + "PACK_KEYS", + "PARTIAL", + "PASSWORD", + "POINT", + "POLYGON", + "PRECISION", + "PREPARE", + "PREV", + "PRIVILEGES", + "PROCEDURE", + "PROCESS", + "PROCESSLIST", + "PURGE", + "QUERY", + "QUICK", + "RAID0", + "RAID_CHUNKS", + "RAID_CHUNKSIZE", + "RAID_TYPE", + "READ", + "REAL", + "REGEXP", + "RELAY_LOG_FILE", + "RELAY_LOG_POS", + "RELAY_THREAD", + "RELOAD", + "RENAME", + "REPAIR", + "REPEATABLE", + "REPLICATION", + "REQUIRE", + "RESET", + "RESTORE", + "RETURNS", + "REVOKE", + "RLIKE", + "ROLLUP", + "ROWS", + "ROW_FORMAT", + "RTREE", + "SAVEPOINT", + "SECOND", + "SECOND_MICROSECOND", + "SEPARATOR", + "SERIAL", + "SERIALIZABLE", + "SESSION", + "SHARE", + "SHOW", + "SHUTDOWN", + "SIGNED", + "SIMPLE", + "SLAVE", + "SMALLINT", + "SOME", + "SONAME", + "SOUNDS", + "SPATIAL", + "SQL_BIG_RESULT", + "SQL_BUFFER_RESULT", + "SQL_CACHE", + "SQL_CALC_FOUND_ROWS", + "SQL_NO_CACHE", + "SQL_SMALL_RESULT", + "SQL_THREAD", + "SSL", + "START", + "STARTING", + "STATUS", + "STOP", + "STORAGE", + "STRAIGHT_JOIN", + "STRING", + "STRIPED", + "SUBJECT", + "SUPER", + "TABLES", + "TABLESPACE", + "TERMINATED", + "TEXT", + "TIME", + "TIMESTAMP", + "TINYBLOB", + "TINYINT", + "TINYTEXT", + "TRAILING", + "TRUE", + "TRUNCATE", + "TYPE", + "TYPES", + "UNCOMMITTED", + "UNICODE", + "UNLOCK", + "UNSIGNED", + "UNTIL", + "USAGE", + "USE", + "USER", + "USER_RESOURCES", + "USE_FRM", + "UTC_DATE", + "UTC_TIME", + "UTC_TIMESTAMP", + "VALUE", + "VARBINARY", + "VARCHAR", + "VARCHARACTER", + "VARIABLES", + "VARYING", + "WARNINGS", + "WITH", + "WORK", + "WRITE", + "X509", + "YEAR", + "YEAR_MONTH", + "ZEROFILL", + 0 + }; +} diff --git a/kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.cpp b/kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.cpp new file mode 100644 index 00000000..2702626a --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.cpp @@ -0,0 +1,298 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "mysqlpreparedstatement.h" +#include <kdebug.h> +#include <errmsg.h> + +using namespace KexiDB; + +// For example prepared MySQL statement code see: +// http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-execute.html + +MySqlPreparedStatement::MySqlPreparedStatement(StatementType type, ConnectionInternal& conn, + FieldList& fields) + : KexiDB::PreparedStatement(type, conn, fields) + , MySqlConnectionInternal(conn.connection) +#ifdef KEXI_USE_MYSQL_STMT + , m_statement(0) + , m_mysqlBind(0) +#endif + , m_resetRequired(false) +{ +// KexiDBDrvDbg << "MySqlPreparedStatement: Construction" << endl; + + mysql_owned = false; + mysql = dynamic_cast<KexiDB::MySqlConnectionInternal&>(conn).mysql; //copy + m_tempStatementString = generateStatementString(); + + if (!init()) + done(); +} + +bool MySqlPreparedStatement::init() +{ + if (m_tempStatementString.isEmpty()) + return false; +#ifdef KEXI_USE_MYSQL_STMT + m_statement = mysql_stmt_init(mysql); + if (!m_statement) { +//! @todo err 'out of memory' + return false; + } + res = mysql_stmt_prepare(m_statement, + (const char*)m_tempStatementString, m_tempStatementString.length()); + if (0 != res) { +//! @todo use mysql_stmt_error(stmt); to show error + return false; + } + + m_realParamCount = mysql_stmt_param_count(m_statement); + if (m_realParamCount<=0) { +//! @todo err + return false; + } + m_mysqlBind = new MYSQL_BIND[ m_realParamCount ]; + memset(m_mysqlBind, 0, sizeof(MYSQL_BIND)*m_realParamCount); //safe? +#endif + return true; +} + + +MySqlPreparedStatement::~MySqlPreparedStatement() +{ + done(); +} + +void MySqlPreparedStatement::done() +{ +#ifdef KEXI_USE_MYSQL_STMT + if (m_statement) { +//! @todo handle errors of mysql_stmt_close()? + mysql_stmt_close(m_statement); + m_statement = 0; + } + delete m_mysqlBind; + m_mysqlBind = 0; +#endif +} + +#ifdef KEXI_USE_MYSQL_STMT +#define BIND_NULL { \ + m_mysqlBind[arg].buffer_type = MYSQL_TYPE_NULL; \ + m_mysqlBind[arg].buffer = 0; \ + m_mysqlBind[arg].buffer_length = 0; \ + m_mysqlBind[arg].is_null = &dummyNull; \ + m_mysqlBind[arg].length = &str_length; } +#endif + +bool MySqlPreparedStatement::execute() +{ +#ifdef KEXI_USE_MYSQL_STMT + if (!m_statement || m_realParamCount<=0) + return false; + if ( mysql_stmt_errno(m_statement) == CR_SERVER_LOST ) { + //sanity: connection lost: reconnect +//! @todo KexiDB::Connection should be reconnected as well! + done(); + if (!init()) { + done(); + return false; + } + } + + if (m_resetRequired) { + mysql_stmt_reset(m_statement); + res = sqlite3_reset(prepared_st_handle); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + m_resetRequired = false; + } + + int arg = 0; + bool dummyNull = true; + unsigned long str_length; + KexiDB::Field *field; + + Field::List _dummy; + Field::ListIterator itFields(_dummy); + //for INSERT, we're iterating over inserting values + //for SELECT, we're iterating over WHERE conditions + if (m_type == SelectStatement) + itFields = *m_whereFields; + else if (m_type == InsertStatement) + itFields = m_fields->fieldsIterator(); + else + assert(0); //impl. error + + for (QValueListConstIterator<QVariant> it = m_args.constBegin(); + (field = itFields.current()) && arg < m_realParamCount; ++it, ++itFields, arg++) + { + if (it==m_args.constEnd() || (*it).isNull()) {//no value to bind or the value is null: bind NULL + BIND_NULL; + continue; + } + if (field->isTextType()) { +//! @todo optimize +m_stringBuffer[ 1024 ]; ??? + char *str = qstrncpy(m_stringBuffer, (const char*)(*it).toString().utf8(), 1024); + m_mysqlBind[arg].buffer_type = MYSQL_TYPE_STRING; + m_mysqlBind[arg].buffer = m_stringBuffer; + m_mysqlBind[arg].is_null = (my_bool*)0; + m_mysqlBind[arg].buffer_length = 1024; //? + m_mysqlBind[arg].length = &str_length; + } + else switch (field->type()) { + case KexiDB::Field::Byte: + case KexiDB::Field::ShortInteger: + case KexiDB::Field::Integer: + { +//! @todo what about unsigned > INT_MAX ? + bool ok; + const int value = (*it).toInt(&ok); + if (ok) { + if (field->type()==KexiDB::Field::Byte) + m_mysqlBind[arg].buffer_type = MYSQL_TYPE_TINY; + else if (field->type()==KexiDB::Field::ShortInteger) + m_mysqlBind[arg].buffer_type = MYSQL_TYPE_SHORT; + else if (field->type()==KexiDB::Field::Integer) + m_mysqlBind[arg].buffer_type = MYSQL_TYPE_LONG; + + m_mysqlBind[arg].is_null = (my_bool*)0; + m_mysqlBind[arg].length = 0; + + res = sqlite3_bind_int(prepared_st_handle, arg, value); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + } + else + BIND_NULL; + break; + } + case KexiDB::Field::Float: + case KexiDB::Field::Double: + res = sqlite3_bind_double(prepared_st_handle, arg, (*it).toDouble()); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + break; + case KexiDB::Field::BigInteger: + { +//! @todo what about unsigned > LLONG_MAX ? + bool ok; + Q_LLONG value = (*it).toLongLong(&ok); + if (ok) { + res = sqlite3_bind_int64(prepared_st_handle, arg, value); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + } + else { + res = sqlite3_bind_null(prepared_st_handle, arg); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + } + break; + } + case KexiDB::Field::Boolean: + res = sqlite3_bind_text(prepared_st_handle, arg, + QString::number((*it).toBool() ? 1 : 0).latin1(), + 1, SQLITE_TRANSIENT /*??*/); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + break; + case KexiDB::Field::Time: + res = sqlite3_bind_text(prepared_st_handle, arg, + (*it).toTime().toString(Qt::ISODate).latin1(), + sizeof("HH:MM:SS"), SQLITE_TRANSIENT /*??*/); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + break; + case KexiDB::Field::Date: + res = sqlite3_bind_text(prepared_st_handle, arg, + (*it).toDate().toString(Qt::ISODate).latin1(), + sizeof("YYYY-MM-DD"), SQLITE_TRANSIENT /*??*/); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + break; + case KexiDB::Field::DateTime: + res = sqlite3_bind_text(prepared_st_handle, arg, + (*it).toDateTime().toString(Qt::ISODate).latin1(), + sizeof("YYYY-MM-DDTHH:MM:SS"), SQLITE_TRANSIENT /*??*/); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + break; + case KexiDB::Field::BLOB: + { + const QByteArray byteArray((*it).toByteArray()); + res = sqlite3_bind_blob(prepared_st_handle, arg, + (const char*)byteArray, byteArray.size(), SQLITE_TRANSIENT /*??*/); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + break; + } + default: + KexiDBWarn << "PreparedStatement::execute(): unsupported field type: " + << field->type() << " - NULL value bound to column #" << arg << endl; + res = sqlite3_bind_null(prepared_st_handle, arg); + if (SQLITE_OK != res) { + //! @todo msg? + return false; + } + } //switch + } + + //real execution + res = sqlite3_step(prepared_st_handle); + m_resetRequired = true; + if (m_type == InsertStatement && res == SQLITE_DONE) { + return true; + } + if (m_type == SelectStatement) { + //fetch result + + //todo + } +#else + m_resetRequired = true; + if (connection->insertRecord(*m_fields, m_args)) { + return true; + } + +#endif //KEXI_USE_MYSQL_STMT + return false; +} diff --git a/kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.h b/kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.h new file mode 100644 index 00000000..01478e9e --- /dev/null +++ b/kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef MYSQLPREPAREDSTATEMENT_H +#define MYSQLPREPAREDSTATEMENT_H + +#include <kexidb/preparedstatement.h> +#include "mysqlconnection_p.h" + +//todo 1.1 - unfinished: #define KEXI_USE_MYSQL_STMT +// for 1.0 we're using unoptimized version + +namespace KexiDB +{ + +/*! Implementation of prepared statements for MySQL driver. */ +class MySqlPreparedStatement : public PreparedStatement, public MySqlConnectionInternal +{ + public: + MySqlPreparedStatement(StatementType type, ConnectionInternal& conn, FieldList& fields); + + virtual ~MySqlPreparedStatement(); + + virtual bool execute(); + + QCString m_tempStatementString; + +#ifdef KEXI_USE_MYSQL_STMT + int m_realParamCount; + MYSQL_STMT *m_statement; + MYSQL_BIND *m_mysqlBind; +#endif + bool m_resetRequired : 1; + + protected: + bool init(); + void done(); +}; +} +#endif |