summaryrefslogtreecommitdiffstats
path: root/kexi/kexidb/drivers/mySQL
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/kexidb/drivers/mySQL
downloadkoffice-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.am33
-rw-r--r--kexi/kexidb/drivers/mySQL/kexidb_mysqldriver.desktop11
-rw-r--r--kexi/kexidb/drivers/mySQL/mySQL.pro28
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlconnection.cpp208
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlconnection.h87
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlconnection_p.cpp175
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlconnection_p.h101
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlcursor.cpp218
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlcursor.h68
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqldriver.cpp212
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqldriver.h59
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlkeywords.cpp338
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.cpp298
-rw-r--r--kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.h56
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