File indexing completed on 2022-11-29 19:02:22

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