|
|
|
/* 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 TQ_WS_WIN
|
|
|
|
# include <mysql/config-win.h>
|
|
|
|
#endif
|
|
|
|
#include <mysql_version.h>
|
|
|
|
#include <mysql.h>
|
|
|
|
#define BOOL bool
|
|
|
|
|
|
|
|
#include <tqvariant.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqdict.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(TQObject *parent, const char *name, const TQStringList &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_RETQUIRED_TO_KNOW_IF_THE_RESULT_IS_EMPTY=false;
|
|
|
|
beh->USING_DATABASE_RETQUIRED_TO_CONNECT=false;
|
|
|
|
beh->TQUOTATION_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 TQString &n) const
|
|
|
|
{
|
|
|
|
return n.lower()=="mysql" || Driver::isSystemObjectName(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MySqlDriver::drv_isSystemFieldName(const TQString&) const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString MySqlDriver::escapeString(const TQString& 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].tqunicode();
|
|
|
|
if (ch == '\\' || ch == '\'' || ch == '"' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\b' || ch == '\0')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i >= old_length) { //no characters to escape
|
|
|
|
return TQString::fromLatin1("'") + str + TQString::fromLatin1("'");
|
|
|
|
}
|
|
|
|
|
|
|
|
TQChar *new_string = new TQChar[ 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].tqunicode();
|
|
|
|
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 '
|
|
|
|
TQString result(new_string, new_length);
|
|
|
|
delete [] new_string;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString MySqlDriver::escapeBLOB(const TQByteArray& array) const
|
|
|
|
{
|
|
|
|
return KexiDB::escapeBLOB(array, KexiDB::BLOBEscape0xHex);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQCString MySqlDriver::escapeString(const TQCString& str) const
|
|
|
|
{
|
|
|
|
//! @todo optimize using mysql_real_escape_string()?
|
|
|
|
//! see http://dev.mysql.com/doc/refman/5.0/en/string-syntax.html
|
|
|
|
|
|
|
|
return TQCString("'")+TQCString(str)
|
|
|
|
.replace( '\\', "\\\\" )
|
|
|
|
.replace( '\'', "\\''" )
|
|
|
|
.replace( '"', "\\\"" )
|
|
|
|
+ TQCString("'");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Add back-ticks to an identifier, and replace any back-ticks within
|
|
|
|
* the name with single quotes.
|
|
|
|
*/
|
|
|
|
TQString MySqlDriver::drv_escapeIdentifier( const TQString& str) const {
|
|
|
|
return TQString(str).replace('`', "'");
|
|
|
|
}
|
|
|
|
|
|
|
|
TQCString MySqlDriver::drv_escapeIdentifier( const TQCString& str) const {
|
|
|
|
return TQCString(str).replace('`', "'");
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "mysqldriver.moc"
|
|
|
|
|