File indexing completed on 2025-04-27 04:21:46
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 }