File indexing completed on 2024-12-08 10:15:21
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003-2018 Jarosław Staniek <staniek@kde.org> 0003 0004 This program is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this program; see the file COPYING. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KDbDriver.h" 0021 #include "KDbAdmin.h" 0022 #include "KDbConnectionData.h" 0023 #include "KDbConnection.h" 0024 #include "KDbConnectionOptions.h" 0025 #include "KDbDriverManager_p.h" 0026 #include "KDbDriverMetaData.h" 0027 #include "KDbDriver_p.h" 0028 #include "KDbDriverBehavior.h" 0029 #include "KDbError.h" 0030 #include "KDbExpression.h" 0031 #include "kdb_debug.h" 0032 0033 #include <algorithm> 0034 0035 /*! @internal Used in KDbDriver::defaultSqlTypeName(int) 0036 when we do not have KDbDriver instance yet, or when we cannot get one */ 0037 static const char* const KDb_defaultSqlTypeNames[] = { 0038 "InvalidType", 0039 "Byte", 0040 "ShortInteger", 0041 "Integer", 0042 "BigInteger", 0043 "Boolean", 0044 "Date", 0045 "DateTime", 0046 "Time", 0047 "Float", 0048 "Double", 0049 "Text", 0050 "LongText", 0051 "BLOB" 0052 }; 0053 0054 //--------------------------------------------- 0055 0056 KDbDriver::KDbDriver(QObject *parent, const QVariantList &args) 0057 : QObject(parent) 0058 , d(new KDbDriverPrivate(this)) 0059 { 0060 Q_UNUSED(args); 0061 d->driverBehavior.typeNames.resize(KDbField::LastType + 1); 0062 } 0063 0064 KDbDriver::~KDbDriver() 0065 { 0066 // make a copy because d->connections will be touched by ~KDbConnection 0067 QSet<KDbConnection*> connections(d->connections); 0068 qDeleteAll(connections); 0069 d->connections.clear(); 0070 delete d; 0071 // kdbDebug() << "ok"; 0072 } 0073 0074 KDbDriverBehavior *KDbDriver::behavior() 0075 { 0076 return &d->driverBehavior; 0077 } 0078 0079 const KDbDriverBehavior *KDbDriver::behavior() const 0080 { 0081 return &d->driverBehavior; 0082 } 0083 0084 bool KDbDriver::isValid() 0085 { 0086 clearResult(); 0087 QString inv_impl(tr("Invalid database driver's \"%1\" implementation.").arg(metaData()->name())); 0088 QString not_init(tr("Value of \"%1\" is not initialized for the driver.")); 0089 if (d->driverBehavior.ROW_ID_FIELD_NAME.isEmpty()) { 0090 m_result = KDbResult(ERR_INVALID_DRIVER_IMPL, 0091 inv_impl + QLatin1Char(' ') 0092 + not_init.arg(QLatin1String("KDbDriverBehavior::ROW_ID_FIELD_NAME"))); 0093 return false; 0094 } 0095 return true; 0096 } 0097 0098 const QSet<KDbConnection*> KDbDriver::connections() const 0099 { 0100 return d->connections; 0101 } 0102 0103 const KDbDriverMetaData* KDbDriver::metaData() const 0104 { 0105 return d->metaData; 0106 } 0107 0108 int KDbDriver::features() const 0109 { 0110 return d->driverBehavior.features; 0111 } 0112 0113 bool KDbDriver::transactionsSupported() const 0114 { 0115 return d->driverBehavior.features & (SingleTransactions | MultipleTransactions); 0116 } 0117 0118 KDbAdminTools& KDbDriver::adminTools() const 0119 { 0120 if (!d->adminTools) 0121 d->adminTools = drv_createAdminTools(); 0122 return *d->adminTools; 0123 } 0124 0125 KDbAdminTools* KDbDriver::drv_createAdminTools() const 0126 { 0127 return new KDbAdminTools(); //empty impl. 0128 } 0129 0130 QString KDbDriver::sqlTypeName(KDbField::Type type, const KDbField &field) const 0131 { 0132 Q_UNUSED(field); 0133 if (type > KDbField::InvalidType && type <= KDbField::LastType) { /*sanity*/ 0134 return d->driverBehavior.typeNames[type]; 0135 } 0136 return d->driverBehavior.typeNames[KDbField::InvalidType]; 0137 } 0138 0139 KDbConnection *KDbDriver::createConnection(const KDbConnectionData& connData, 0140 const KDbConnectionOptions &options) 0141 { 0142 clearResult(); 0143 if (!isValid()) 0144 return nullptr; 0145 0146 KDbConnection *conn = drv_createConnection(connData, options); 0147 0148 //! @todo needed? connData->setDriverId(id()); 0149 d->connections.insert(conn); 0150 return conn; 0151 } 0152 0153 KDbConnection *KDbDriver::createConnection(const KDbConnectionData& connData) 0154 { 0155 return createConnection(connData, KDbConnectionOptions()); 0156 } 0157 0158 KDbConnection* KDbDriver::removeConnection(KDbConnection *conn) 0159 { 0160 clearResult(); 0161 if (d->connections.remove(conn)) 0162 return conn; 0163 return nullptr; 0164 } 0165 0166 QString KDbDriver::defaultSqlTypeName(KDbField::Type type) 0167 { 0168 if (type > KDbField::LastType) 0169 return QLatin1String("Null"); 0170 return QLatin1String(KDb_defaultSqlTypeNames[type]); 0171 } 0172 0173 bool KDbDriver::isKDbSystemObjectName(const QString& name) 0174 { 0175 if (!name.startsWith(QLatin1String("kexi__"), Qt::CaseInsensitive)) 0176 return false; 0177 return KDbConnection::kdbSystemTableNames().contains(name, Qt::CaseInsensitive); 0178 } 0179 0180 bool KDbDriver::isSystemFieldName(const QString& name) const 0181 { 0182 if (!d->driverBehavior.ROW_ID_FIELD_NAME.isEmpty() 0183 && 0 == name.compare(d->driverBehavior.ROW_ID_FIELD_NAME, Qt::CaseInsensitive)) 0184 { 0185 return true; 0186 } 0187 return drv_isSystemFieldName(name); 0188 } 0189 0190 KDbEscapedString valueToSqlInternal(const KDbDriver *driver, KDbField::Type ftype, const QVariant& v) 0191 { 0192 if (v.isNull() || ftype == KDbField::Null) { 0193 return KDbEscapedString("NULL"); 0194 } 0195 switch (ftype) { 0196 case KDbField::Text: 0197 case KDbField::LongText: { 0198 return driver ? driver->escapeString(v.toString()) 0199 : KDbEscapedString(KDb::escapeString(v.toString())); 0200 } 0201 case KDbField::Byte: 0202 case KDbField::ShortInteger: 0203 case KDbField::Integer: 0204 case KDbField::BigInteger: 0205 return KDbEscapedString(v.toByteArray()); 0206 case KDbField::Float: 0207 case KDbField::Double: { 0208 if (v.type() == QVariant::String) { 0209 //workaround for values stored as string that should be casted to floating-point 0210 KDbEscapedString s(v.toByteArray()); 0211 return s.replace(',', '.'); 0212 } 0213 return KDbEscapedString(v.toByteArray()); 0214 } 0215 //! @todo here special encoding method needed 0216 case KDbField::Boolean: 0217 return driver 0218 ? KDbEscapedString(v.toInt() == 0 ? KDbDriverPrivate::behavior(driver)->BOOLEAN_FALSE_LITERAL 0219 : KDbDriverPrivate::behavior(driver)->BOOLEAN_TRUE_LITERAL) 0220 : KDbEscapedString(v.toInt() == 0 ? "FALSE" : "TRUE"); 0221 case KDbField::Time: 0222 return driver ? driver->timeToSql(v) : KDb::timeToSql(v); 0223 case KDbField::Date: 0224 return driver ? driver->dateToSql(v) : KDb::dateToSql(v); 0225 case KDbField::DateTime: 0226 return driver ? driver->dateTimeToSql(v) : KDb::dateTimeToSql(v); 0227 case KDbField::BLOB: { 0228 if (v.toByteArray().isEmpty()) { 0229 return KDbEscapedString("NULL"); 0230 } 0231 if (v.type() == QVariant::String) { 0232 return driver ? driver->escapeBLOB(v.toString().toUtf8()) 0233 : KDbEscapedString(KDb::escapeBLOB(v.toString().toUtf8(), KDb::BLOBEscapingType::ZeroXHex)); 0234 } 0235 return driver ? driver->escapeBLOB(v.toByteArray()) 0236 : KDbEscapedString(KDb::escapeBLOB(v.toByteArray(), KDb::BLOBEscapingType::ZeroXHex)); 0237 } 0238 case KDbField::InvalidType: 0239 return KDbEscapedString("!INVALIDTYPE!"); 0240 default: 0241 kdbDebug() << KDbEscapedString("UNKNOWN!"); 0242 } 0243 return KDbEscapedString(); 0244 } 0245 0246 KDbEscapedString KDbDriver::valueToSql(KDbField::Type ftype, const QVariant& v) const 0247 { 0248 //! @note it was compatible with SQLite: https://www.sqlite.org/lang_datefunc.html 0249 return valueToSqlInternal(this, ftype, v); 0250 } 0251 0252 KDbEscapedString KDbDriver::dateToSql(const QVariant &v) const 0253 { 0254 return KDb::dateToIsoString(v); 0255 } 0256 0257 KDbEscapedString KDbDriver::timeToSql(const QVariant& v) const 0258 { 0259 return KDb::timeToIsoString(v); 0260 } 0261 0262 KDbEscapedString KDbDriver::dateTimeToSql(const QVariant& v) const 0263 { 0264 return KDb::dateTimeToIsoString(v); 0265 } 0266 0267 KDbEscapedString KDbDriver::dateTimeToSql(const QDateTime& v) const 0268 { 0269 return dateTimeToSql(QVariant(v)); 0270 } 0271 0272 QString KDbDriver::escapeIdentifier(const QString& str) const 0273 { 0274 return QLatin1Char(d->driverBehavior.OPENING_QUOTATION_MARK_BEGIN_FOR_IDENTIFIER) 0275 + drv_escapeIdentifier(str) 0276 + QLatin1Char(d->driverBehavior.CLOSING_QUOTATION_MARK_BEGIN_FOR_IDENTIFIER); 0277 } 0278 0279 QByteArray KDbDriver::escapeIdentifier(const QByteArray& str) const 0280 { 0281 return d->driverBehavior.OPENING_QUOTATION_MARK_BEGIN_FOR_IDENTIFIER 0282 + drv_escapeIdentifier(str) 0283 + d->driverBehavior.CLOSING_QUOTATION_MARK_BEGIN_FOR_IDENTIFIER; 0284 } 0285 0286 KDbUtils::Property KDbDriver::internalProperty(const QByteArray& name) const 0287 { 0288 return d->driverBehavior.properties.property(name); 0289 } 0290 0291 QList<QByteArray> KDbDriver::internalPropertyNames() const 0292 { 0293 QList<QByteArray> names(d->driverBehavior.properties.names()); 0294 std::sort(names.begin(), names.end()); 0295 return names; 0296 } 0297 0298 void KDbDriver::initDriverSpecificKeywords(const char* const* keywords) 0299 { 0300 d->driverSpecificSqlKeywords.setStrings(keywords); 0301 } 0302 0303 KDbEscapedString KDbDriver::addLimitTo1(const KDbEscapedString& sql, bool add) 0304 { 0305 return add ? (sql + " LIMIT 1") : sql; 0306 } 0307 0308 bool KDbDriver::isDriverSpecificKeyword(const QByteArray& word) const 0309 { 0310 return d->driverSpecificSqlKeywords.contains(word); 0311 } 0312 0313 void KDbDriver::setMetaData(const KDbDriverMetaData *metaData) 0314 { 0315 d->metaData = metaData; 0316 d->driverBehavior.initInternalProperties(); 0317 } 0318 0319 KDbEscapedString KDbDriver::hexFunctionToString( 0320 const KDbNArgExpression &args, 0321 KDbQuerySchemaParameterValueListIterator* params, 0322 KDb::ExpressionCallStack* callStack) const 0323 { 0324 return KDbFunctionExpression::toString(QLatin1String("HEX"), this, args, params, callStack); 0325 } 0326 0327 KDbEscapedString KDbDriver::ifnullFunctionToString( 0328 const KDbNArgExpression &args, 0329 KDbQuerySchemaParameterValueListIterator* params, 0330 KDb::ExpressionCallStack* callStack) const 0331 { 0332 return KDbFunctionExpression::toString(QLatin1String("IFNULL"), this, args, params, callStack); 0333 } 0334 0335 KDbEscapedString KDbDriver::lengthFunctionToString( 0336 const KDbNArgExpression &args, 0337 KDbQuerySchemaParameterValueListIterator* params, 0338 KDb::ExpressionCallStack* callStack) const 0339 { 0340 return KDbFunctionExpression::toString(QLatin1String("LENGTH"), this, args, params, callStack); 0341 } 0342 0343 KDbEscapedString KDbDriver::greatestOrLeastFunctionToString( 0344 const QString &name, 0345 const KDbNArgExpression &args, 0346 KDbQuerySchemaParameterValueListIterator* params, 0347 KDb::ExpressionCallStack* callStack) const 0348 { 0349 return KDbFunctionExpression::toString(name, this, args, params, callStack); 0350 } 0351 0352 KDbEscapedString KDbDriver::randomFunctionToString( 0353 const KDbNArgExpression &args, 0354 KDbQuerySchemaParameterValueListIterator* params, 0355 KDb::ExpressionCallStack* callStack) const 0356 { 0357 static QLatin1String randomStatic("()"); 0358 if (!args.isNull() || args.argCount() < 1 ) { 0359 return KDbEscapedString(d->driverBehavior.RANDOM_FUNCTION + randomStatic); 0360 } 0361 if (args.argCount() != 2) { 0362 return KDbEscapedString(); 0363 } 0364 const KDbEscapedString x(args.arg(0).toString(this, params, callStack)); 0365 const KDbEscapedString y(args.arg(1).toString(this, params, callStack)); 0366 static KDbEscapedString floorRandomStatic("+FLOOR("); 0367 static KDbEscapedString floorRandomStatic2("()*("); 0368 static KDbEscapedString floorRandomStatic3(")))"); 0369 return KDbEscapedString('(') + x + floorRandomStatic + d->driverBehavior.RANDOM_FUNCTION 0370 + floorRandomStatic2 + y + QLatin1Char('-') + x + floorRandomStatic3; 0371 } 0372 0373 KDbEscapedString KDbDriver::ceilingOrFloorFunctionToString( 0374 const QString &name, 0375 const KDbNArgExpression &args, 0376 KDbQuerySchemaParameterValueListIterator* params, 0377 KDb::ExpressionCallStack* callStack) const 0378 { 0379 return KDbFunctionExpression::toString(name, this, args, params, callStack); 0380 } 0381 0382 KDbEscapedString KDbDriver::unicodeFunctionToString( 0383 const KDbNArgExpression &args, 0384 KDbQuerySchemaParameterValueListIterator* params, 0385 KDb::ExpressionCallStack* callStack) const 0386 { 0387 return KDbFunctionExpression::toString(QLatin1String("UNICODE"), this, args, params, callStack); 0388 } 0389 0390 KDbEscapedString KDbDriver::concatenateFunctionToString(const KDbBinaryExpression &args, 0391 KDbQuerySchemaParameterValueListIterator* params, 0392 KDb::ExpressionCallStack* callStack) const 0393 { 0394 return args.left().toString(this, params, callStack) + KDbEscapedString("||") 0395 + args.right().toString(this, params, callStack); 0396 } 0397 0398 //--------------- 0399 0400 Q_GLOBAL_STATIC_WITH_ARGS( 0401 KDbUtils::StaticSetOfStrings, 0402 KDb_kdbSqlKeywords, 0403 (KDbDriverPrivate::kdbSQLKeywords) ) 0404 0405 KDB_EXPORT bool KDb::isKDbSqlKeyword(const QByteArray& word) 0406 { 0407 return KDb_kdbSqlKeywords->contains(word.toUpper()); 0408 } 0409 0410 KDB_EXPORT QString KDb::escapeIdentifier(const KDbDriver* driver, 0411 const QString& str) 0412 { 0413 return driver ? driver->escapeIdentifier(str) 0414 : KDb::escapeIdentifier(str); 0415 } 0416 0417 KDB_EXPORT QByteArray KDb::escapeIdentifier(const KDbDriver* driver, 0418 const QByteArray& str) 0419 { 0420 return driver ? driver->escapeIdentifier(str) 0421 : KDb::escapeIdentifier(str); 0422 }