File indexing completed on 2024-05-26 04:44:47

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003-2012 Jarosław Staniek <staniek@kde.org>
0003 
0004    Based on nexp.cpp : Parser module of Python-like language
0005    (C) 2001 Jarosław Staniek, MIMUW (www.mimuw.edu.pl)
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021  */
0022 
0023 #include "KDbExpression.h"
0024 #include "KDb.h"
0025 #include "KDbDriver.h"
0026 #include "KDbQuerySchema.h"
0027 #include "KDbParser_p.h"
0028 #include "kdb_debug.h"
0029 
0030 KDbVariableExpressionData::KDbVariableExpressionData()
0031  : KDbExpressionData()
0032  , field(nullptr)
0033  , tablePositionForField(-1)
0034  , tableForQueryAsterisk(nullptr)
0035 {
0036     ExpressionDebug << "VariableExpressionData" << ref;
0037 }
0038 
0039 KDbVariableExpressionData::KDbVariableExpressionData(const QString& aName)
0040  : KDbExpressionData()
0041  , name(aName)
0042  , field(nullptr)
0043  , tablePositionForField(-1)
0044  , tableForQueryAsterisk(nullptr)
0045 {
0046    ExpressionDebug << "VariableExpressionData" << ref;
0047 }
0048 
0049 KDbVariableExpressionData::~KDbVariableExpressionData()
0050 {
0051     ExpressionDebug << "~VariableExpressionData" << ref;
0052 }
0053 
0054 KDbVariableExpressionData* KDbVariableExpressionData::clone()
0055 {
0056     ExpressionDebug << "VariableExpressionData::clone" << *this;
0057     return new KDbVariableExpressionData(*this);
0058 }
0059 
0060 void KDbVariableExpressionData::debugInternal(QDebug dbg, KDb::ExpressionCallStack* callStack) const
0061 {
0062     Q_UNUSED(callStack);
0063     dbg.nospace() << qPrintable(QString::fromLatin1("VariableExp(\"%1\",type=%2)")
0064         .arg(name, field ? KDbDriver::defaultSqlTypeName(type())
0065                              : QLatin1String("FIELD_NOT_DEFINED_YET")));
0066 }
0067 
0068 KDbEscapedString KDbVariableExpressionData::toStringInternal(
0069                                         const KDbDriver *driver,
0070                                         KDbQuerySchemaParameterValueListIterator* params,
0071                                         KDb::ExpressionCallStack* callStack) const
0072 {
0073     Q_UNUSED(driver);
0074     Q_UNUSED(params);
0075     Q_UNUSED(callStack);
0076     return KDbEscapedString(name);
0077 }
0078 
0079 void KDbVariableExpressionData::getQueryParameters(QList<KDbQuerySchemaParameter>* params)
0080 {
0081     Q_UNUSED(params);
0082 }
0083 
0084 //! We're assuming it's called after VariableExpr::validate()
0085 KDbField::Type KDbVariableExpressionData::typeInternal(KDb::ExpressionCallStack* callStack) const
0086 {
0087     Q_UNUSED(callStack);
0088     if (field)
0089         return field->type();
0090 
0091     //BTW, asterisks are not stored in VariableExpr outside of parser, so ok.
0092     return KDbField::InvalidType;
0093 }
0094 
0095 static void validateImplError(KDbParseInfo *parseInfo_, const QString &errmsg)
0096 {
0097     KDbParseInfoInternal *parseInfo = static_cast<KDbParseInfoInternal*>(parseInfo_);
0098     parseInfo->setErrorMessage(QLatin1String("Implementation error"));
0099     parseInfo->setErrorDescription(errmsg);
0100 }
0101 
0102 bool KDbVariableExpressionData::validateInternal(KDbParseInfo *parseInfo_, KDb::ExpressionCallStack* callStack)
0103 {
0104     Q_UNUSED(callStack);
0105     KDbParseInfoInternal *parseInfo = static_cast<KDbParseInfoInternal*>(parseInfo_);
0106     field = nullptr;
0107     tablePositionForField = -1;
0108     tableForQueryAsterisk = nullptr;
0109 
0110     /* taken from parser's addColumn(): */
0111     kdbDebug() << "checking variable name: " << name;
0112     QString tableName, fieldName;
0113     if (!KDb::splitToTableAndFieldParts(name, &tableName, &fieldName,
0114                                         KDb::SetFieldNameIfNoTableName))
0115     {
0116         return false;
0117     }
0118     //! @todo shall we also support db name?
0119     if (tableName.isEmpty()) {//fieldname only
0120         if (fieldName == QLatin1String("*")) {
0121             return true;
0122         }
0123 
0124         //find first table that has this field
0125         KDbField *firstField = nullptr;
0126         foreach(KDbTableSchema *table, *parseInfo->querySchema()->tables()) {
0127             KDbField *f = table->field(fieldName);
0128             if (f) {
0129                 if (!firstField) {
0130                     firstField = f;
0131                 } else if (f->table() != firstField->table()) {
0132                     //ambiguous field name
0133                     parseInfo->setErrorMessage(tr("Ambiguous field name"));
0134                     parseInfo->setErrorDescription(
0135                                        tr("Both table \"%1\" and \"%2\" have defined \"%3\" field. "
0136                                           "Use \"<tableName>.%4\" notation to specify table name.",
0137                                           "Note: translate also <tableName>")
0138                                           .arg(firstField->table()->name(), f->table()->name(),
0139                                                fieldName, fieldName));
0140                     return false;
0141                 }
0142             }
0143         }
0144         if (!firstField) {
0145             parseInfo->setErrorMessage(tr("Field not found"));
0146             parseInfo->setErrorDescription(
0147                 tr("Could not find table containing field \"%1\".").arg(fieldName));
0148             return false;
0149         }
0150         //ok
0151         field = firstField; //store
0152         return true;
0153     }
0154 
0155     //table.fieldname or tableAlias.fieldname
0156     KDbTableSchema *ts = parseInfo->querySchema()->table(tableName);
0157     int tablePosition = -1;
0158     if (ts) {//table.fieldname
0159         //check if "table" is covered by an alias
0160         const QList<int> tPositions = parseInfo->querySchema()->tablePositions(tableName);
0161         QString tableAlias;
0162         bool covered = true;
0163         foreach(int position, tPositions) {
0164             tableAlias = parseInfo->querySchema()->tableAlias(position);
0165             if (tableAlias.isEmpty() || tableAlias.toLower() == tableName) {
0166                 covered = false; //uncovered
0167                 break;
0168             }
0169             kdbDebug() << " --" << "covered by " << tableAlias << " alias";
0170         }
0171         if (covered) {
0172             parseInfo->setErrorMessage(tr("Could not access the table directly using its name"));
0173             parseInfo->setErrorDescription(
0174                                tr("Table name \"%1\" is covered by aliases. "
0175                                   "Instead of \"%2\", \"%3\" can be used.")
0176                                   .arg(tableName,
0177                                        tableName + QLatin1Char('.') + fieldName,
0178                                        tableAlias + QLatin1Char('.') + fieldName));
0179             return false;
0180         }
0181         if (!tPositions.isEmpty()) {
0182             tablePosition = tPositions.first();
0183         }
0184     }
0185     else {//try to find tableAlias
0186         tablePosition = parseInfo->querySchema()->tablePositionForAlias(tableName);
0187         if (tablePosition >= 0) {
0188             ts = parseInfo->querySchema()->tables()->at(tablePosition);
0189             if (ts) {
0190 //    kdbDebug() << " --it's a tableAlias.name";
0191             }
0192         }
0193     }
0194 
0195     if (!ts) {
0196         parseInfo->setErrorMessage(tr("Table not found"));
0197         parseInfo->setErrorDescription(tr("Unknown table \"%1\".").arg(tableName));
0198         return false;
0199     }
0200 
0201     const QList<int> positionsList(parseInfo->tablesAndAliasesForName(tableName));
0202     if (positionsList.isEmpty()) {  //for sanity
0203         validateImplError(parseInfo,
0204             QString::fromLatin1("%1.%2, !positionsList ").arg(tableName, fieldName));
0205         return false;
0206     }
0207 
0208     //it's a table.*
0209     if (fieldName == QLatin1String("*")) {
0210         if (positionsList.count() > 1) {
0211             parseInfo->setErrorMessage(tr("Ambiguous \"%1.*\" expression").arg(tableName));
0212             parseInfo->setErrorDescription(tr("More than one \"%1\" table or alias defined.").arg(tableName));
0213             return false;
0214         }
0215         tableForQueryAsterisk = ts;
0216         return true;
0217     }
0218 
0219 // kdbDebug() << " --it's a table.name";
0220     KDbField *realField = ts->field(fieldName);
0221     if (!realField) {
0222         parseInfo->setErrorMessage(tr("Field not found"));
0223         parseInfo->setErrorDescription(
0224             tr("Table \"%1\" has no \"%2\" field.").arg(tableName, fieldName));
0225         return false;
0226     }
0227 
0228     // check if table or alias is used twice and both have the same column
0229     // (so the column is ambiguous)
0230     if (positionsList.count() > 1) {
0231         parseInfo->setErrorMessage(tr("Ambiguous \"%1.%2\" expression").arg(tableName, fieldName));
0232         parseInfo->setErrorDescription(
0233             tr("More than one \"%1\" table or alias defined containing \"%2\" field.")
0234                               .arg(tableName, fieldName));
0235         return false;
0236     }
0237     field = realField; //store
0238     tablePositionForField = tablePosition;
0239     return true;
0240 }
0241 
0242 //=========================================
0243 
0244 KDbVariableExpression::KDbVariableExpression()
0245  : KDbExpression(new KDbVariableExpressionData)
0246 {
0247     ExpressionDebug << "KDbVariableExpression() ctor" << *this;
0248 }
0249 
0250 KDbVariableExpression::KDbVariableExpression(const QString& name)
0251         : KDbExpression(new KDbVariableExpressionData(name),
0252               KDb::VariableExpression, KDbToken()/*undefined*/)
0253 {
0254 }
0255 
0256 KDbVariableExpression::KDbVariableExpression(const KDbVariableExpression& expr)
0257         : KDbExpression(expr)
0258 {
0259 }
0260 
0261 KDbVariableExpression::KDbVariableExpression(KDbExpressionData* data)
0262     : KDbExpression(data)
0263 {
0264     ExpressionDebug << "KDbVariableExpression ctor (KDbExpressionData*)" << *this;
0265 }
0266 
0267 KDbVariableExpression::KDbVariableExpression(const ExplicitlySharedExpressionDataPointer &ptr)
0268     : KDbExpression(ptr)
0269 {
0270 }
0271 
0272 KDbVariableExpression::~KDbVariableExpression()
0273 {
0274 }
0275 
0276 QString KDbVariableExpression::name() const
0277 {
0278     return d->convert<KDbVariableExpressionData>()->name;
0279 }
0280 
0281 KDbField *KDbVariableExpression::field() const
0282 {
0283     return d->convert<KDbVariableExpressionData>()->field;
0284 }
0285 
0286 int KDbVariableExpression::tablePositionForField() const
0287 {
0288     return d->convert<KDbVariableExpressionData>()->tablePositionForField;
0289 }
0290 
0291 KDbTableSchema *KDbVariableExpression::tableForQueryAsterisk() const
0292 {
0293     return d->convert<KDbVariableExpressionData>()->tableForQueryAsterisk;
0294 }