File indexing completed on 2024-04-21 15:29:53
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003-2016 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 "KDbQuerySchema.h" 0026 #include "KDbDriver.h" 0027 #include "KDbParser_p.h" 0028 #include "kdb_debug.h" 0029 #include "generated/sqlparser.h" 0030 0031 KDbBinaryExpressionData::KDbBinaryExpressionData() 0032 : KDbExpressionData() 0033 { 0034 ExpressionDebug << "BinaryExpressionData" << ref; 0035 } 0036 0037 KDbBinaryExpressionData::~KDbBinaryExpressionData() 0038 { 0039 } 0040 0041 bool KDbBinaryExpressionData::validateInternal(KDbParseInfo *parseInfo, KDb::ExpressionCallStack* callStack) 0042 { 0043 if (children.count() != 2) 0044 return false; 0045 0046 if (!left()->validate(parseInfo, callStack)) 0047 return false; 0048 if (!right()->validate(parseInfo, callStack)) 0049 return false; 0050 0051 //update type for query parameters 0052 //! @todo IMPORTANT: update type for query parameters 0053 #if 0 0054 if (left()->isQueryParameter()) { 0055 KDbQueryParameterExpression queryParameter = left()->toQueryParameter(); 0056 queryParameter->setType(left()->type()); 0057 } 0058 if (right()->isQueryParameter()) { 0059 KDbQueryParameterExpression queryParameter = right()->toQueryParameter(); 0060 queryParameter->setType(right()->type()); 0061 } 0062 #endif 0063 if (typeInternal(callStack) == KDbField::InvalidType) { 0064 parseInfo->setErrorMessage(tr("Incompatible types of arguments")); 0065 parseInfo->setErrorDescription( 0066 tr("Expression \"%1\" requires compatible types of arguments. " 0067 "Specified arguments are of type %2 and %3.", 0068 "Binary expression arguments type error") 0069 .arg(toStringInternal(nullptr, nullptr, callStack).toString(), 0070 KDbField::typeName(left()->type()), 0071 KDbField::typeName(right()->type()))); 0072 return false; 0073 } 0074 return true; 0075 } 0076 0077 KDbField::Type KDbBinaryExpressionData::typeInternal(KDb::ExpressionCallStack* callStack) const 0078 { 0079 if (children.count() != 2 || expressionClass == KDb::UnknownExpression) 0080 return KDbField::InvalidType; 0081 const KDbField::Type lt = left()->type(callStack); 0082 const KDbField::Type rt = right()->type(callStack); 0083 if (lt == KDbField::InvalidType || rt == KDbField::InvalidType) 0084 return KDbField::InvalidType; 0085 0086 const bool ltNull = lt == KDbField::Null; 0087 const bool rtNull = rt == KDbField::Null; 0088 const bool ltText = KDbField::isTextType(lt); 0089 const bool rtText = KDbField::isTextType(rt); 0090 const bool ltInt = KDbField::isIntegerType(lt); 0091 const bool rtInt = KDbField::isIntegerType(rt); 0092 const bool ltFP = KDbField::isFPNumericType(lt); 0093 const bool rtFP = KDbField::isFPNumericType(rt); 0094 const bool ltBool = lt == KDbField::Boolean; 0095 const bool rtBool = rt == KDbField::Boolean; 0096 const KDbField::TypeGroup ltGroup = KDbField::typeGroup(lt); 0097 const KDbField::TypeGroup rtGroup = KDbField::typeGroup(rt); 0098 const bool lAny = left()->convertConst<KDbQueryParameterExpressionData>(); 0099 const bool rAny = right()->convertConst<KDbQueryParameterExpressionData>(); 0100 0101 if (ltNull || rtNull) { 0102 switch (token.value()) { 0103 //! @todo add general support, e.g. for "NULL AND (1 == 1)"; for now we only support 0104 //! constants because there's no evaluation and operations with NULL depend on whether we have TRUE or FALSE 0105 //! See https://www.postgresql.org/docs/9.4/static/functions-logical.html 0106 //! https://dev.mysql.com/doc/refman/5.0/en/logical-operators.html 0107 case OR: { 0108 const KDbConstExpressionData *leftConst = left()->convertConst<KDbConstExpressionData>(); 0109 const KDbConstExpressionData *rightConst = right()->convertConst<KDbConstExpressionData>(); 0110 if ((ltBool && leftConst && leftConst->value.toBool()) // true OR NULL is true 0111 || (rtBool && rightConst && rightConst->value.toBool())) // NULL OR true is true 0112 { 0113 return KDbField::Boolean; 0114 } 0115 else if ((ltBool && leftConst && !leftConst->value.toBool()) // false OR NULL is NULL 0116 || (rtBool && rightConst && !rightConst->value.toBool()) // NULL OR false is NULL 0117 || lAny // Any OR NULL may be NULL 0118 || rAny) // NULL OR Any may be NULL 0119 //! @todo Any OR NULL may be also TRUE -- but this needs support of fuzzy/multivalue types 0120 //! @todo NULL OR Any may be also TRUE -- but this needs support of fuzzy/multivalue types 0121 { 0122 return KDbField::Null; 0123 } 0124 break; 0125 } 0126 case AND: { 0127 const KDbConstExpressionData *leftConst = left()->convertConst<KDbConstExpressionData>(); 0128 const KDbConstExpressionData *rightConst = right()->convertConst<KDbConstExpressionData>(); 0129 if ((ltBool && leftConst && !leftConst->value.toBool()) // false AND NULL is false 0130 || (rtBool && rightConst && !rightConst->value.toBool())) // NULL AND false is false 0131 { 0132 return KDbField::Boolean; 0133 } 0134 else if ((ltBool && leftConst && leftConst->value.toBool()) // true AND NULL is NULL 0135 || (rtBool && rightConst && rightConst->value.toBool()) // NULL AND true is NULL 0136 || lAny // Any AND NULL may be NULL 0137 || rAny) // NULL AND Any may be NULL 0138 //! @todo Any AND NULL may be also FALSE -- but this needs support of fuzzy/multivalue types 0139 //! @todo NULL AND Any may be also FALSE -- but this needs support of fuzzy/multivalue types 0140 { 0141 return KDbField::Null; 0142 } 0143 break; 0144 } 0145 case XOR: {// Logical XOR. Returns NULL if either operand is NULL. For non-NULL operands, 0146 // evaluates to 1 if an odd number of operands is nonzero, otherwise 0 is returned. 0147 // a XOR b is mathematically equal to (a AND (NOT b)) OR ((NOT a) and b). 0148 // https://dev.mysql.com/doc/refman/5.0/en/logical-operators.html#operator_xor 0149 return KDbField::Null; 0150 } 0151 default: 0152 return KDbField::Null; 0153 } 0154 } 0155 0156 switch (token.value()) { 0157 case OR: 0158 case AND: 0159 case XOR: { 0160 if (ltNull && rtNull) { 0161 return KDbField::Null; 0162 } else if ((ltBool && rtBool) 0163 || (ltBool && rAny) 0164 || (lAny && rtBool) 0165 || (lAny && rAny)) 0166 { 0167 return KDbField::Boolean; 0168 } 0169 return KDbField::InvalidType; 0170 } 0171 case '+': 0172 case CONCATENATION: 0173 if (lt == KDbField::Text && rt == KDbField::Text) { 0174 return KDbField::Text; 0175 } 0176 else if ((ltText && rtText) 0177 || (ltText && rAny) 0178 || (lAny && rtText)) 0179 { 0180 return KDbField::LongText; 0181 } 0182 else if ((ltText && rtNull) 0183 || (ltNull && rtText) 0184 || (lAny && rtNull) 0185 || (ltNull && rAny)) 0186 { 0187 return KDbField::Null; 0188 } else if (token.value() == CONCATENATION) { 0189 if (lAny && rAny) { 0190 return KDbField::LongText; 0191 } 0192 return KDbField::InvalidType; 0193 } 0194 break; // '+' can still be handled below for non-text types 0195 default:; 0196 } 0197 0198 if (expressionClass == KDb::RelationalExpression) { 0199 if ((ltText && rtText) 0200 || (ltText && rAny) 0201 || (lAny && rtText) 0202 || (lAny && rAny) 0203 0204 || (ltInt && rtInt) 0205 || (ltInt && rAny) 0206 || (lAny && rtInt) 0207 0208 || (ltFP && rtFP) || (ltInt && rtFP) || (ltFP && rtInt) 0209 || (ltFP && rAny) || (lAny && rtFP) 0210 0211 || (ltBool && rtBool) || (ltBool && rtInt) || (ltInt && rtBool) 0212 || (ltBool && rAny) || (lAny && rtBool) 0213 0214 || (ltBool && rtFP) || (ltFP && rtBool) 0215 0216 || (ltGroup == KDbField::DateTimeGroup && rtGroup == KDbField::DateTimeGroup) 0217 || (ltGroup == KDbField::DateTimeGroup && rAny) 0218 || (lAny && rtGroup == KDbField::DateTimeGroup)) 0219 { 0220 return KDbField::Boolean; 0221 } 0222 return KDbField::InvalidType; 0223 } 0224 0225 if (expressionClass == KDb::ArithmeticExpression) { 0226 if (lAny && rAny) { 0227 return KDbField::Integer; 0228 } else if ((ltInt && rtInt) 0229 || (ltInt && rAny) 0230 || (lAny && rtInt)) 0231 { 0232 /* From documentation of KDb::maximumForIntegerFieldTypes(): 0233 In case of KDb::ArithmeticExpression: 0234 returned type may not fit to the result of evaluated expression that involves the arguments. 0235 For example, 100 is within Byte type, maximumForIntegerFieldTypes(Byte, Byte) is Byte but result 0236 of 100 * 100 exceeds the range of Byte. 0237 0238 Solution: for types smaller than Integer (e.g. Byte and ShortInteger) we are returning 0239 Integer type. 0240 */ 0241 KDbField::Type t; 0242 if (lAny) { 0243 t = rt; 0244 } else if (rAny) { 0245 t = lt; 0246 } else { 0247 t = KDb::maximumForIntegerFieldTypes(lt, rt); 0248 } 0249 if (t == KDbField::Byte || t == KDbField::ShortInteger) { 0250 return KDbField::Integer; 0251 } 0252 return t; 0253 } 0254 0255 switch (token.value()) { 0256 case '&': 0257 case BITWISE_SHIFT_RIGHT: 0258 case BITWISE_SHIFT_LEFT: 0259 if ((ltFP && rtFP) 0260 || (ltFP && rAny) //! @todo can be other Integer too 0261 || (lAny && rtFP)) //! @todo can be other Integer too 0262 { 0263 return KDbField::Integer; 0264 } 0265 else if ((ltFP && rtInt) // inherit from right 0266 || (lAny && rtInt)) 0267 { 0268 return rt; 0269 } 0270 else if ((ltInt && rtFP) // inherit from left 0271 || (ltInt && rAny)) 0272 { 0273 return lt; 0274 } 0275 break; 0276 default:; 0277 } 0278 0279 /* inherit floating point (Float or Double) type */ 0280 if (ltFP && (rtInt || lt == rt || rAny)) 0281 return lt; 0282 if (rtFP && (ltInt || lt == rt || lAny)) 0283 return rt; 0284 } 0285 return KDbField::InvalidType; 0286 } 0287 0288 KDbBinaryExpressionData* KDbBinaryExpressionData::clone() 0289 { 0290 ExpressionDebug << "BinaryExpressionData::clone" << *this; 0291 return new KDbBinaryExpressionData(*this); 0292 } 0293 0294 void KDbBinaryExpressionData::debugInternal(QDebug dbg, KDb::ExpressionCallStack* callStack) const 0295 { 0296 dbg.nospace() << "BinaryExp(class=" 0297 << expressionClassName(expressionClass) 0298 << ","; 0299 if (children.count() == 2 && left().constData()) { 0300 left()->debug(dbg, callStack); 0301 } 0302 else { 0303 dbg.nospace() << "<NONE>"; 0304 } 0305 dbg.nospace() << "," << token << ","; 0306 if (children.count() == 2 && right().constData()) { 0307 right()->debug(dbg, callStack); 0308 } 0309 else { 0310 dbg.nospace() << "<NONE>"; 0311 } 0312 dbg.nospace() << ",type=" << KDbDriver::defaultSqlTypeName(type()) << ")"; 0313 } 0314 0315 KDbEscapedString KDbBinaryExpressionData::toStringInternal( 0316 const KDbDriver *driver, 0317 KDbQuerySchemaParameterValueListIterator* params, 0318 KDb::ExpressionCallStack* callStack) const 0319 { 0320 switch (token.value()) { 0321 case '+': 0322 case CONCATENATION: { 0323 if (driver && KDbField::isTextType(type())) { 0324 const KDbBinaryExpression binaryExpr(const_cast<KDbBinaryExpressionData*>(this)); 0325 return driver->concatenateFunctionToString(binaryExpr, params, callStack); 0326 } 0327 break; 0328 } 0329 default:; 0330 } 0331 0332 #define INFIX(a) \ 0333 (left().constData() ? left()->toString(driver, params, callStack) : KDbEscapedString("<NULL>")) \ 0334 + " " + a + " " + (right().constData() ? right()->toString(driver, params, callStack) : KDbEscapedString("<NULL>")) 0335 return INFIX(token.toString(driver)); 0336 #undef INFIX 0337 } 0338 0339 void KDbBinaryExpressionData::getQueryParameters(QList<KDbQuerySchemaParameter>* params) 0340 { 0341 Q_ASSERT(params); 0342 if (left().constData()) 0343 left()->getQueryParameters(params); 0344 if (right().constData()) 0345 right()->getQueryParameters(params); 0346 } 0347 0348 ExplicitlySharedExpressionDataPointer KDbBinaryExpressionData::left() const 0349 { 0350 return (children.count() > 0) ? children.at(0) : ExplicitlySharedExpressionDataPointer(); 0351 } 0352 ExplicitlySharedExpressionDataPointer KDbBinaryExpressionData::right() const 0353 { 0354 return (children.count() > 1) ? children.at(1) : ExplicitlySharedExpressionDataPointer(); 0355 } 0356 0357 //========================================= 0358 0359 static KDb::ExpressionClass classForArgs(const KDbExpression& leftExpr, 0360 KDbToken token, 0361 const KDbExpression& rightExpr) 0362 { 0363 if (leftExpr.isNull()) { 0364 kdbWarning() << "Setting KDbBinaryExpression to null because left argument is not specified"; 0365 return KDb::UnknownExpression; 0366 } 0367 if (rightExpr.isNull()) { 0368 kdbWarning() << "Setting KDbBinaryExpression to null because right argument is not specified"; 0369 return KDb::UnknownExpression; 0370 } 0371 return KDbExpression::classForToken(token); 0372 } 0373 0374 KDbBinaryExpression::KDbBinaryExpression() 0375 : KDbExpression(new KDbBinaryExpressionData) 0376 { 0377 ExpressionDebug << "KDbBinaryExpression() ctor" << *this; 0378 } 0379 0380 KDbBinaryExpression::KDbBinaryExpression(const KDbExpression& leftExpr, 0381 KDbToken token, 0382 const KDbExpression& rightExpr) 0383 : KDbExpression(new KDbBinaryExpressionData, classForArgs(leftExpr, token, rightExpr), token) 0384 { 0385 if (!isNull()) { 0386 appendChild(leftExpr.d); 0387 appendChild(rightExpr.d); 0388 } 0389 } 0390 0391 KDbBinaryExpression::KDbBinaryExpression(const KDbBinaryExpression& expr) 0392 : KDbExpression(expr) 0393 { 0394 } 0395 0396 KDbBinaryExpression::KDbBinaryExpression(KDbExpressionData* data) 0397 : KDbExpression(data) 0398 { 0399 ExpressionDebug << "KDbBinaryExpression(KDbExpressionData*) ctor" << *this; 0400 } 0401 0402 KDbBinaryExpression::KDbBinaryExpression(const ExplicitlySharedExpressionDataPointer &ptr) 0403 : KDbExpression(ptr) 0404 { 0405 } 0406 0407 KDbBinaryExpression::~KDbBinaryExpression() 0408 { 0409 } 0410 0411 KDbExpression KDbBinaryExpression::left() const 0412 { 0413 return (d->children.count() > 0) ? KDbExpression(d->children.at(0)) : KDbExpression(); 0414 } 0415 0416 void KDbBinaryExpression::setLeft(const KDbExpression& leftExpr) 0417 { 0418 KDbExpression::setLeftOrRight(leftExpr, 0); 0419 } 0420 0421 KDbExpression KDbBinaryExpression::right() const 0422 { 0423 return (d->children.count() > 1) ? KDbExpression(d->children.at(1)) : KDbExpression(); 0424 } 0425 0426 void KDbBinaryExpression::setRight(const KDbExpression& rightExpr) 0427 { 0428 KDbExpression::setLeftOrRight(rightExpr, 1); 0429 }