kexi
driver.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <kexidb/driver.h>
00021 #include <kexidb/driver_p.h>
00022 #include <kexidb/drivermanager.h>
00023 #include <kexidb/drivermanager_p.h>
00024 #include "error.h"
00025 #include "drivermanager.h"
00026 #include "connection.h"
00027 #include "connectiondata.h"
00028
00029 #include <qfileinfo.h>
00030
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033
00034 #include <assert.h>
00035
00036 using namespace KexiDB;
00037
00040 QValueVector<QString> dflt_typeNames;
00041
00042
00043
00044
00045
00046 DriverBehaviour::DriverBehaviour()
00047 : UNSIGNED_TYPE_KEYWORD("UNSIGNED")
00048 , AUTO_INCREMENT_FIELD_OPTION("AUTO_INCREMENT")
00049 , AUTO_INCREMENT_PK_FIELD_OPTION("AUTO_INCREMENT PRIMARY KEY")
00050 , SPECIAL_AUTO_INCREMENT_DEF(false)
00051 , AUTO_INCREMENT_REQUIRES_PK(false)
00052 , ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE(false)
00053 , QUOTATION_MARKS_FOR_IDENTIFIER('"')
00054 , USING_DATABASE_REQUIRED_TO_CONNECT(true)
00055 , _1ST_ROW_READ_AHEAD_REQUIRED_TO_KNOW_IF_THE_RESULT_IS_EMPTY(false)
00056 , SELECT_1_SUBQUERY_SUPPORTED(false)
00057 , SQL_KEYWORDS(0)
00058 {
00059
00060 }
00061
00062 //---------------------------------------------
00063
00064 Driver::Driver( QObject *parent, const char *name, const QStringList & )
00065 : QObject( parent, name )
00066 , Object()
00067 , beh( new DriverBehaviour() )
00068 , d( new DriverPrivate() )
00069 {
00070 d->connections.setAutoDelete(false);
00071 //TODO: reasonable size
00072 d->connections.resize(101);
00073 d->typeNames.resize(Field::LastType + 1);
00074
00075 d->initKexiKeywords();
00076 }
00077
00078
00079 Driver::~Driver()
00080 {
00081 DriverManagerInternal::self()->aboutDelete( this );
00082 // KexiDBDbg << "Driver::~Driver()" << endl;
00083 QPtrDictIterator<Connection> it( d->connections );
00084 Connection *conn;
00085 while ( (conn = it.toFirst()) ) {
00086 delete conn;
00087 }
00088 delete beh;
00089 delete d;
00090 // KexiDBDbg << "Driver::~Driver() ok" << endl;
00091 }
00092
00093 bool Driver::isValid()
00094 {
00095 clearError();
00096 if (KexiDB::versionMajor() != versionMajor()
00097 || KexiDB::versionMinor() != versionMinor())
00098 {
00099 setError(ERR_INCOMPAT_DRIVER_VERSION,
00100 i18n("Incompatible database driver's \"%1\" version: found version %2, expected version %3.")
00101 .arg(name())
00102 .arg(QString("%1.%2").arg(versionMajor()).arg(versionMinor()))
00103 .arg(QString("%1.%2").arg(KexiDB::versionMajor()).arg(KexiDB::versionMinor())));
00104 return false;
00105 }
00106
00107 QString inv_impl = i18n("Invalid database driver's \"%1\" implementation:\n").arg(name());
00108 QString not_init = i18n("Value of \"%1\" is not initialized for the driver.");
00109 if (beh->ROW_ID_FIELD_NAME.isEmpty()) {
00110 setError(ERR_INVALID_DRIVER_IMPL, inv_impl + not_init.arg("DriverBehaviour::ROW_ID_FIELD_NAME"));
00111 return false;
00112 }
00113
00114 return true;
00115 }
00116
00117 const QPtrList<Connection> Driver::connectionsList() const
00118 {
00119 QPtrList<Connection> clist;
00120 QPtrDictIterator<Connection> it( d->connections );
00121 for( ; it.current(); ++it )
00122 clist.append( &(*it) );
00123 return clist;
00124 }
00125
00126 QString Driver::fileDBDriverMimeType() const
00127 { return d->fileDBDriverMimeType; }
00128
00129 QString Driver::defaultFileBasedDriverMimeType()
00130 { return QString::fromLatin1("application/x-kexiproject-sqlite3"); }
00131
00132 QString Driver::defaultFileBasedDriverName()
00133 {
00134 DriverManager dm;
00135 return dm.lookupByMime(Driver::defaultFileBasedDriverMimeType()).lower();
00136 }
00137
00138 const KService* Driver::service() const
00139 { return d->service; }
00140
00141 bool Driver::isFileDriver() const
00142 { return d->isFileDriver; }
00143
00144 int Driver::features() const
00145 { return d->features; }
00146
00147 bool Driver::transactionsSupported() const
00148 { return d->features & (SingleTransactions | MultipleTransactions); }
00149
00150 QString Driver::sqlTypeName(int id_t, int ) const
00151 {
00152 if (id_t > Field::InvalidType && id_t <= Field::LastType)
00153 return d->typeNames[(id_t>0 && id_t<=Field::LastType) ? id_t : Field::InvalidType ];
00154
00155 return d->typeNames[Field::InvalidType];
00156 }
00157
00158 Connection *Driver::createConnection( ConnectionData &conn_data, int options )
00159 {
00160 clearError();
00161 if (!isValid())
00162 return 0;
00163
00164 if (d->isFileDriver) {
00165 if (conn_data.fileName().isEmpty()) {
00166 setError(ERR_MISSING_DB_LOCATION, i18n("File name expected for file-based database driver.") );
00167 return 0;
00168 }
00169 }
00170
00171 Connection *conn = drv_createConnection( conn_data );
00172
00173 conn->setReadOnly(options & ReadOnlyConnection);
00174
00175 conn_data.driverName = name();
00176 d->connections.insert( conn, conn );
00177 return conn;
00178 }
00179
00180 Connection* Driver::removeConnection( Connection *conn )
00181 {
00182 clearError();
00183 return d->connections.take( conn );
00184 }
00185
00186 QString Driver::defaultSQLTypeName(int id_t)
00187 {
00188 if (id_t==Field::Null)
00189 return "Null";
00190 if (dflt_typeNames.isEmpty()) {
00191 dflt_typeNames.resize(Field::LastType + 1);
00192 dflt_typeNames[Field::Byte]="Byte";
00193 dflt_typeNames[Field::ShortInteger]="ShortInteger";
00194 dflt_typeNames[Field::Integer]="Integer";
00195 dflt_typeNames[Field::BigInteger]="BigInteger";
00196 dflt_typeNames[Field::Boolean]="Boolean";
00197 dflt_typeNames[Field::Date]="Date";
00198 dflt_typeNames[Field::DateTime]="DateTime";
00199 dflt_typeNames[Field::Time]="Time";
00200 dflt_typeNames[Field::Float]="Float";
00201 dflt_typeNames[Field::Double]="Double";
00202 dflt_typeNames[Field::Text]="Text";
00203 dflt_typeNames[Field::LongText]="Text";
00204 dflt_typeNames[Field::BLOB]="BLOB";
00205 }
00206 return dflt_typeNames[id_t];
00207 }
00208
00209 bool Driver::isSystemObjectName( const QString& n ) const
00210 {
00211 return Driver::isKexiDBSystemObjectName(n);
00212 }
00213
00214 bool Driver::isKexiDBSystemObjectName( const QString& n )
00215 {
00216 if (!n.lower().startsWith("kexi__"))
00217 return false;
00218 const QStringList list( Connection::kexiDBSystemTableNames() );
00219 return list.find(n.lower())!=list.constEnd();
00220 }
00221
00222 bool Driver::isSystemFieldName( const QString& n ) const
00223 {
00224 if (!beh->ROW_ID_FIELD_NAME.isEmpty() && n.lower()==beh->ROW_ID_FIELD_NAME.lower())
00225 return true;
00226 return drv_isSystemFieldName(n);
00227 }
00228
00229 QString Driver::valueToSQL( uint ftype, const QVariant& v ) const
00230 {
00231 if (v.isNull())
00232 return "NULL";
00233 switch (ftype) {
00234 case Field::Byte:
00235 case Field::ShortInteger:
00236 case Field::Integer:
00237 case Field::Float:
00238 case Field::Double:
00239 case Field::BigInteger:
00240 return v.toString();
00241
00242 case Field::Boolean:
00243 return QString::number(v.toInt()?1:0);
00244 case Field::Time:
00245 return QString("\'")+v.toTime().toString(Qt::ISODate)+"\'";
00246 case Field::Date:
00247 return QString("\'")+v.toDate().toString(Qt::ISODate)+"\'";
00248 case Field::DateTime:
00249 return dateTimeToSQL( v.toDateTime() );
00250 case Field::Text:
00251 case Field::LongText: {
00252 QString s = v.toString();
00253 return escapeString(s);
00254 }
00255 case Field::BLOB: {
00256 if (v.type()==QVariant::String)
00257 return escapeBLOB(v.toString().utf8());
00258 return escapeBLOB(v.toByteArray());
00259 }
00260 case Field::InvalidType:
00261 return "!INVALIDTYPE!";
00262 default:
00263 KexiDBDbg << "Driver::valueToSQL(): UNKNOWN!" << endl;
00264 return QString::null;
00265 }
00266 return QString::null;
00267 }
00268
00269 QVariant Driver::propertyValue( const QCString& propName ) const
00270 {
00271 return d->properties[propName.lower()];
00272 }
00273
00274 QString Driver::propertyCaption( const QCString& propName ) const
00275 {
00276 return d->propertyCaptions[propName.lower()];
00277 }
00278
00279 QValueList<QCString> Driver::propertyNames() const
00280 {
00281 QValueList<QCString> names = d->properties.keys();
00282 qHeapSort(names);
00283 return names;
00284 }
00285
00286 QString Driver::escapeIdentifier(const QString& str, int options) const
00287 {
00288 QCString cstr = str.latin1();
00289 return QString(escapeIdentifier(cstr, options));
00290 }
00291
00292 QCString Driver::escapeIdentifier(const QCString& str, int options) const
00293 {
00294 bool needOuterQuotes = false;
00295
00296
00297
00298 if(options & EscapeAlways)
00299 needOuterQuotes = true;
00300
00301
00302 else if(!d->driverSQLDict)
00303 needOuterQuotes = true;
00304
00305
00306 else if(d->kexiSQLDict->find(str))
00307 needOuterQuotes = true;
00308
00309
00310
00311 else if((options & EscapeDriver) && d->driverSQLDict->find(str))
00312 needOuterQuotes = true;
00313
00314
00315 else if(str.find(' ') != -1)
00316 needOuterQuotes = true;
00317
00318 if(needOuterQuotes && (options & EscapeKexi)) {
00319 const char quote = '"';
00320 return quote + QCString(str).replace( quote, "\"\"" ) + quote;
00321 }
00322 else if (needOuterQuotes) {
00323 const char quote = beh->QUOTATION_MARKS_FOR_IDENTIFIER.latin1();
00324 return quote + drv_escapeIdentifier(str) + quote;
00325 } else {
00326 return drv_escapeIdentifier(str);
00327 }
00328 }
00329
00330 void Driver::initSQLKeywords(int hashSize) {
00331
00332 if(!d->driverSQLDict && beh->SQL_KEYWORDS != 0) {
00333 d->initDriverKeywords(beh->SQL_KEYWORDS, hashSize);
00334 }
00335 }
00336
00337 #define BLOB_ESCAPING_TYPE_USE_X 0
00338 #define BLOB_ESCAPING_TYPE_USE_0x 1
00339 #define BLOB_ESCAPING_TYPE_USE_OCTAL 2
00340
00341 QString Driver::escapeBLOBInternal(const QByteArray& array, int type) const
00342 {
00343 const int size = array.size();
00344 int escaped_length = size*2 + 2;
00345 if (type == BLOB_ESCAPING_TYPE_USE_X)
00346 escaped_length += 1;
00347 QString str;
00348 str.reserve(escaped_length);
00349 if (str.capacity() < (uint)escaped_length) {
00350 KexiDBWarn << "KexiDB::Driver::escapeBLOB(): no enough memory (cannot allocate "<< \
00351 escaped_length<<" chars)" << endl;
00352 return QString::fromLatin1("NULL");
00353 }
00354 if (type == BLOB_ESCAPING_TYPE_USE_X)
00355 str = QString::fromLatin1("X'");
00356 else if (type == BLOB_ESCAPING_TYPE_USE_0x)
00357 str = QString::fromLatin1("0x");
00358 else if (type == BLOB_ESCAPING_TYPE_USE_OCTAL)
00359 str = QString::fromLatin1("'");
00360
00361 int new_length = str.length();
00362 if (type == BLOB_ESCAPING_TYPE_USE_OCTAL) {
00363
00364
00365
00366 for (int i = 0; i < size; i++) {
00367 const unsigned char val = array[i];
00368 if (val<32 || val>=127 || val==39 || val==92) {
00369 str[new_length++] = '\\';
00370 str[new_length++] = '\\';
00371 str[new_length++] = '0' + val/64;
00372 str[new_length++] = '0' + (val % 64) / 8;
00373 str[new_length++] = '0' + val % 8;
00374 }
00375 else {
00376 str[new_length++] = val;
00377 }
00378 }
00379 }
00380 else {
00381 for (int i = 0; i < size; i++) {
00382 const unsigned char val = array[i];
00383 str[new_length++] = (val/16) < 10 ? ('0'+(val/16)) : ('A'+(val/16)-10);
00384 str[new_length++] = (val%16) < 10 ? ('0'+(val%16)) : ('A'+(val%16)-10);
00385 }
00386 }
00387 if (type == BLOB_ESCAPING_TYPE_USE_X || type == BLOB_ESCAPING_TYPE_USE_OCTAL)
00388 str[new_length++] = '\'';
00389 return str;
00390 }
00391
00392 #include "driver.moc"
00393
|