kexi

expression.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    Based on nexp.cpp : Parser module of Python-like language
00005    (C) 2001 Jaroslaw Staniek, MIMUW (www.mimuw.edu.pl)
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022 
00023 #include "expression.h"
00024 #include "utils.h"
00025 #include "parser/sqlparser.h"
00026 #include "parser/parser_p.h"
00027 
00028 #include <ctype.h>
00029 
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 
00033 #include <qdatetime.h>
00034 
00035 KEXI_DB_EXPORT QString KexiDB::exprClassName(int c)
00036 {
00037     if (c==KexiDBExpr_Unary)
00038         return "Unary";
00039     else if (c==KexiDBExpr_Arithm)
00040         return "Arithm";
00041     else if (c==KexiDBExpr_Logical)
00042         return "Logical";
00043     else if (c==KexiDBExpr_Relational)
00044         return "Relational";
00045     else if (c==KexiDBExpr_SpecialBinary)
00046         return "SpecialBinary";
00047     else if (c==KexiDBExpr_Const)
00048         return "Const";
00049     else if (c==KexiDBExpr_Variable)
00050         return "Variable";
00051     else if (c==KexiDBExpr_Function)
00052         return "Function";
00053     else if (c==KexiDBExpr_Aggregation)
00054         return "Aggregation";
00055     else if (c==KexiDBExpr_TableList)
00056         return "TableList";
00057     else if (c==KexiDBExpr_QueryParameter)
00058         return "QueryParameter";
00059     
00060     return "Unknown";
00061 }
00062 
00063 using namespace KexiDB;
00064 
00065 //=========================================
00066 
00067 BaseExpr::BaseExpr(int token) 
00068  : m_cl(KexiDBExpr_Unknown)
00069  , m_par(0)
00070  , m_token(token)
00071 {
00072 }
00073 
00074 BaseExpr::~BaseExpr()
00075 {
00076 }
00077 
00078 Field::Type BaseExpr::type()
00079 {
00080     return Field::InvalidType;
00081 }
00082 
00083 QString BaseExpr::debugString()
00084 {
00085     return QString("BaseExpr(%1,type=%1)").arg(m_token).arg(Driver::defaultSQLTypeName(type()));
00086 }
00087 
00088 bool BaseExpr::validate(ParseInfo& /*parseInfo*/)
00089 {
00090     return true;
00091 }
00092 
00093 extern const char * const tname(int offset);
00094 #define safe_tname(token) ((token>=255 && token<=__LAST_TOKEN) ? tname(token-255) : "")
00095 
00096 QString BaseExpr::tokenToDebugString(int token)
00097 {
00098     if (token < 254) {
00099         if (isprint(token))
00100             return QString(QChar(uchar(token)));
00101         else
00102             return QString::number(token);
00103     }
00104     return QString(safe_tname(token));
00105 }
00106 
00107 QString BaseExpr::tokenToString()
00108 {
00109     if (m_token < 255 && isprint(m_token))
00110         return tokenToDebugString();
00111     return QString::null;
00112 }
00113 
00114 NArgExpr* BaseExpr::toNArg() { return dynamic_cast<NArgExpr*>(this); }
00115 UnaryExpr* BaseExpr::toUnary() { return dynamic_cast<UnaryExpr*>(this); }
00116 BinaryExpr* BaseExpr::toBinary() { return dynamic_cast<BinaryExpr*>(this); }
00117 ConstExpr* BaseExpr::toConst() { return dynamic_cast<ConstExpr*>(this); }
00118 VariableExpr* BaseExpr::toVariable() { return dynamic_cast<VariableExpr*>(this); }
00119 FunctionExpr* BaseExpr::toFunction() { return dynamic_cast<FunctionExpr*>(this); }
00120 QueryParameterExpr* BaseExpr::toQueryParameter() { return dynamic_cast<QueryParameterExpr*>(this); }
00121 
00122 //=========================================
00123 
00124 NArgExpr::NArgExpr(int aClass, int token)
00125  : BaseExpr(token)
00126 {
00127     m_cl = aClass;
00128     list.setAutoDelete(true);
00129 }
00130 
00131 NArgExpr::NArgExpr(const NArgExpr& expr)
00132  : BaseExpr(expr)
00133 {
00134     foreach_list (BaseExpr::ListIterator, it, expr.list)
00135         add( it.current()->copy() );
00136 }
00137 
00138 NArgExpr::~NArgExpr()
00139 {
00140 }
00141 
00142 NArgExpr* NArgExpr::copy() const
00143 {
00144     return new NArgExpr(*this);
00145 }
00146 
00147 QString NArgExpr::debugString()
00148 {
00149     QString s = QString("NArgExpr(")
00150         + "class=" + exprClassName(m_cl);
00151     for ( BaseExpr::ListIterator it(list); it.current(); ++it ) {
00152         s+=", ";
00153         s+=it.current()->debugString();
00154     }
00155     s+=")";
00156     return s;
00157 }
00158 
00159 QString NArgExpr::toString( QuerySchemaParameterValueListIterator* params )
00160 {
00161     QString s;
00162     s.reserve(256);
00163     foreach_list( BaseExpr::ListIterator, it, list) {
00164         if (!s.isEmpty())
00165             s+=", ";
00166         s+=it.current()->toString(params);
00167     }
00168     return s;
00169 }
00170 
00171 void NArgExpr::getQueryParameters(QuerySchemaParameterList& params)
00172 {
00173     foreach_list( BaseExpr::ListIterator, it, list)
00174         it.current()->getQueryParameters(params);
00175 }
00176 
00177 BaseExpr* NArgExpr::arg(int nr)
00178 {
00179     return list.at(nr); 
00180 }
00181 
00182 void NArgExpr::add(BaseExpr *expr)
00183 {
00184     list.append(expr);
00185     expr->setParent(this);
00186 }
00187 
00188 void NArgExpr::prepend(BaseExpr *expr)
00189 {
00190     list.prepend(expr);
00191     expr->setParent(this);
00192 }
00193 
00194 int NArgExpr::args()
00195 {
00196     return list.count();
00197 }
00198 
00199 bool NArgExpr::validate(ParseInfo& parseInfo)
00200 {
00201     if (!BaseExpr::validate(parseInfo))
00202         return false;
00203 
00204     foreach_list(BaseExpr::ListIterator, it, list) {
00205         if (!it.current()->validate(parseInfo))
00206             return false;
00207     }
00208     return true;
00209 }
00210 
00211 //=========================================
00212 UnaryExpr::UnaryExpr(int token, BaseExpr *arg)
00213  : BaseExpr(token)
00214  , m_arg(arg)
00215 {
00216     m_cl = KexiDBExpr_Unary;
00217     if (m_arg)
00218         m_arg->setParent(this);
00219 }
00220 
00221 UnaryExpr::UnaryExpr(const UnaryExpr& expr)
00222  : BaseExpr(expr)
00223  , m_arg( expr.m_arg ? expr.m_arg->copy() : 0 )
00224 {
00225     if (m_arg)
00226         m_arg->setParent(this);
00227 }
00228 
00229 UnaryExpr::~UnaryExpr()
00230 {
00231     delete m_arg;
00232 }
00233 
00234 UnaryExpr* UnaryExpr::copy() const
00235 {
00236     return new UnaryExpr(*this);
00237 }
00238 
00239 QString UnaryExpr::debugString()
00240 {
00241     return "UnaryExpr('" 
00242         + tokenToDebugString() + "', "
00243         + (m_arg ? m_arg->debugString() : QString("<NONE>")) 
00244         + QString(",type=%1)").arg(Driver::defaultSQLTypeName(type()));
00245 }
00246 
00247 QString UnaryExpr::toString(QuerySchemaParameterValueListIterator* params)
00248 {
00249     if (m_token=='(') //parentheses (special case)
00250         return "(" + (m_arg ? m_arg->toString(params) : "<NULL>") + ")";
00251     if (m_token < 255 && isprint(m_token))
00252         return tokenToDebugString() + (m_arg ? m_arg->toString(params) : "<NULL>");
00253     if (m_token==NOT)
00254         return "NOT " + (m_arg ? m_arg->toString(params) : "<NULL>");
00255     if (m_token==SQL_IS_NULL)
00256         return (m_arg ? m_arg->toString(params) : "<NULL>") + " IS NULL";
00257     if (m_token==SQL_IS_NOT_NULL)
00258         return (m_arg ? m_arg->toString(params) : "<NULL>") + " IS NOT NULL";
00259     return QString("{INVALID_OPERATOR#%1} ").arg(m_token) + (m_arg ? m_arg->toString(params) : "<NULL>");
00260 }
00261 
00262 void UnaryExpr::getQueryParameters(QuerySchemaParameterList& params)
00263 {
00264     if (m_arg)
00265         m_arg->getQueryParameters(params);
00266 }
00267 
00268 Field::Type UnaryExpr::type()
00269 {
00270     //NULL IS NOT NULL : BOOLEAN
00271     //NULL IS NULL : BOOLEAN
00272     switch (m_token) {
00273     case SQL_IS_NULL:
00274     case SQL_IS_NOT_NULL:
00275         return Field::Boolean;
00276     }
00277     const Field::Type t = m_arg->type();
00278     if (t==Field::Null)
00279         return Field::Null;
00280     if (m_token==NOT)
00281         return Field::Boolean;
00282 
00283     return t;
00284 }
00285 
00286 bool UnaryExpr::validate(ParseInfo& parseInfo)
00287 {
00288     if (!BaseExpr::validate(parseInfo))
00289         return false;
00290 
00291     if (!m_arg->validate(parseInfo))
00292         return false;
00293 
00295 
00296     // update type
00297     if (m_arg->toQueryParameter()) {
00298         m_arg->toQueryParameter()->setType(type());
00299     }
00300 
00301     return true;
00302 #if 0
00303     BaseExpr *n = l.at(0);
00304 
00305     n->check();
00306 /*typ wyniku:
00307         const bool dla "NOT <bool>" (negacja)
00308         int dla "# <str>" (dlugosc stringu)
00309         int dla "+/- <int>"
00310         */
00311     if (is(NOT) && n->nodeTypeIs(TYP_BOOL)) {
00312         node_type=new NConstType(TYP_BOOL);
00313     }
00314     else if (is('#') && n->nodeTypeIs(TYP_STR)) {
00315         node_type=new NConstType(TYP_INT);
00316     }
00317     else if ((is('+') || is('-')) && n->nodeTypeIs(TYP_INT)) {
00318         node_type=new NConstType(TYP_INT);
00319     }
00320     else {
00321         ERR("Niepoprawny argument typu '%s' dla operatora '%s'",
00322             n->nodeTypeName(),is(NOT)?QString("not"):QChar(typ()));
00323     }
00324 #endif
00325 }
00326     
00327 //=========================================
00328 BinaryExpr::BinaryExpr(int aClass, BaseExpr *left_expr, int token, BaseExpr *right_expr)
00329  : BaseExpr(token)
00330  , m_larg(left_expr)
00331  , m_rarg(right_expr)
00332 {
00333     m_cl = aClass;
00334     if (m_larg)
00335         m_larg->setParent(this);
00336     if (m_rarg)
00337         m_rarg->setParent(this);
00338 }
00339 
00340 BinaryExpr::BinaryExpr(const BinaryExpr& expr)
00341  : BaseExpr(expr)
00342  , m_larg( expr.m_larg ? expr.m_larg->copy() : 0 )
00343  , m_rarg( expr.m_rarg ? expr.m_rarg->copy() : 0 )
00344 {
00345 }
00346 
00347 BinaryExpr::~BinaryExpr()
00348 {
00349     delete m_larg;
00350     delete m_rarg;
00351 }
00352 
00353 BinaryExpr* BinaryExpr::copy() const
00354 {
00355     return new BinaryExpr(*this);
00356 }
00357 
00358 bool BinaryExpr::validate(ParseInfo& parseInfo)
00359 {
00360     if (!BaseExpr::validate(parseInfo))
00361         return false;
00362 
00363     if (!m_larg->validate(parseInfo))
00364         return false;
00365     if (!m_rarg->validate(parseInfo))
00366         return false;
00367 
00369 
00370     //update type for query parameters
00371     QueryParameterExpr * queryParameter = m_larg->toQueryParameter();
00372     if (queryParameter)
00373         queryParameter->setType(m_rarg->type());
00374     queryParameter = m_rarg->toQueryParameter();
00375     if (queryParameter)
00376         queryParameter->setType(m_larg->type());
00377 
00378     return true;
00379 }
00380 
00381 Field::Type BinaryExpr::type()
00382 {
00383     const Field::Type lt = m_larg->type(), rt = m_rarg->type();
00384     if (lt==Field::InvalidType || rt == Field::InvalidType)
00385         return Field::InvalidType;
00386     if (lt==Field::Null || rt == Field::Null) {
00387         if (m_token!=OR) //note that NULL OR something   != NULL
00388             return Field::Null;
00389     }
00390 
00391     switch (m_token) {
00392     case BITWISE_SHIFT_RIGHT:
00393     case BITWISE_SHIFT_LEFT:
00394     case CONCATENATION:
00395         return lt;
00396     }
00397 
00398     const bool ltInt = Field::isIntegerType(lt);
00399     const bool rtInt = Field::isIntegerType(rt);
00400     if (ltInt && rtInt)
00401         return KexiDB::maximumForIntegerTypes(lt, rt);
00402 
00403     if (Field::isFPNumericType(lt) && rtInt)
00404         return lt;
00405     if (Field::isFPNumericType(rt) && ltInt)
00406         return rt;
00407     if ((lt==Field::Double || lt==Field::Float) && rtInt)
00408         return lt;
00409     if ((rt==Field::Double || rt==Field::Float) && ltInt)
00410         return rt;
00411 
00412     return Field::Boolean;
00413 }
00414 
00415 QString BinaryExpr::debugString()
00416 {
00417     return QString("BinaryExpr(")
00418         + "class=" + exprClassName(m_cl)
00419         + "," + (m_larg ? m_larg->debugString() : QString("<NONE>")) 
00420         + ",'" + tokenToDebugString() + "',"
00421         + (m_rarg ? m_rarg->debugString() : QString("<NONE>")) 
00422         + QString(",type=%1)").arg(Driver::defaultSQLTypeName(type()));
00423 }
00424 
00425 QString BinaryExpr::tokenToString()
00426 {
00427     if (m_token < 255 && isprint(m_token))
00428         return tokenToDebugString();
00429     // other arithmetic operations: << >>
00430     switch (m_token) {
00431     case BITWISE_SHIFT_RIGHT: return ">>";
00432     case BITWISE_SHIFT_LEFT: return "<<";
00433     // other relational operations: <= >= <> (or !=) LIKE IN
00434     case NOT_EQUAL: return "<>";
00435     case NOT_EQUAL2: return "!=";
00436     case LESS_OR_EQUAL: return "<=";
00437     case GREATER_OR_EQUAL: return ">=";
00438     case LIKE: return "LIKE";
00439     case SQL_IN: return "IN";
00440     // other logical operations: OR (or ||) AND (or &&) XOR
00441     case SIMILAR_TO: return "SIMILAR TO";
00442     case NOT_SIMILAR_TO: return "NOT SIMILAR TO";
00443     case OR: return "OR";
00444     case AND: return "AND";
00445     case XOR: return "XOR";
00446     // other string operations: || (as CONCATENATION)
00447     case CONCATENATION: return "||";
00448     // SpecialBinary "pseudo operators":
00449     /* not handled here */
00450     default:;
00451     }
00452     return QString("{INVALID_BINARY_OPERATOR#%1} ").arg(m_token);
00453 }
00454 
00455 QString BinaryExpr::toString(QuerySchemaParameterValueListIterator* params)
00456 {
00457 #define INFIX(a) \
00458         (m_larg ? m_larg->toString(params) : "<NULL>") + " " + a + " " + (m_rarg ? m_rarg->toString(params) : "<NULL>")
00459     return INFIX(tokenToString());
00460 }
00461 
00462 void BinaryExpr::getQueryParameters(QuerySchemaParameterList& params)
00463 {
00464     if (m_larg)
00465         m_larg->getQueryParameters(params);
00466     if (m_rarg)
00467         m_rarg->getQueryParameters(params);
00468 }
00469 
00470 //=========================================
00471 ConstExpr::ConstExpr( int token, const QVariant& val)
00472 : BaseExpr( token )
00473 , value(val)
00474 {
00475     m_cl = KexiDBExpr_Const;
00476 }
00477 
00478 ConstExpr::ConstExpr(const ConstExpr& expr)
00479  : BaseExpr(expr)
00480  , value(expr.value)
00481 {
00482 }
00483 
00484 ConstExpr::~ConstExpr()
00485 {
00486 }
00487 
00488 ConstExpr* ConstExpr::copy() const
00489 {
00490     return new ConstExpr(*this);
00491 }
00492 
00493 Field::Type ConstExpr::type()
00494 {
00495     if (m_token==SQL_NULL)
00496         return Field::Null;
00497     else if (m_token==INTEGER_CONST) {
00498 //TODO ok?
00499 //TODO: add sign info?
00500         if (value.type() == QVariant::Int || value.type() == QVariant::UInt) {
00501             Q_LLONG v = value.toInt();
00502             if (v <= 0xff && v > -0x80)
00503                 return Field::Byte;
00504             if (v <= 0xffff && v > -0x8000)
00505                 return Field::ShortInteger;
00506             return Field::Integer;
00507         }
00508         return Field::BigInteger;
00509     }
00510     else if (m_token==CHARACTER_STRING_LITERAL) {
00511 //TODO: Field::defaultTextLength() is hardcoded now!
00512         if (value.toString().length() > Field::defaultTextLength())
00513             return Field::LongText;
00514         else
00515             return Field::Text;
00516     }
00517     else if (m_token==REAL_CONST)
00518         return Field::Double;
00519     else if (m_token==DATE_CONST)
00520         return Field::Date;
00521     else if (m_token==DATETIME_CONST)
00522         return Field::DateTime;
00523     else if (m_token==TIME_CONST)
00524         return Field::Time;
00525 
00526     return Field::InvalidType;
00527 }
00528 
00529 QString ConstExpr::debugString()
00530 {
00531     return QString("ConstExpr('") + tokenToDebugString() +"'," + toString()
00532         + QString(",type=%1)").arg(Driver::defaultSQLTypeName(type()));
00533 }
00534 
00535 QString ConstExpr::toString(QuerySchemaParameterValueListIterator* params)
00536 {
00537     Q_UNUSED(params);
00538     if (m_token==SQL_NULL)
00539         return "NULL";
00540     else if (m_token==CHARACTER_STRING_LITERAL)
00541 //TODO: better escaping!
00542         return "'" + value.toString() + "'";
00543     else if (m_token==REAL_CONST)
00544         return QString::number(value.toPoint().x())+"."+QString::number(value.toPoint().y());
00545     else if (m_token==DATE_CONST)
00546         return "'" + value.toDate().toString(Qt::ISODate) + "'";
00547     else if (m_token==DATETIME_CONST)
00548         return "'" + value.toDateTime().date().toString(Qt::ISODate) 
00549             + " " + value.toDateTime().time().toString(Qt::ISODate) + "'";
00550     else if (m_token==TIME_CONST)
00551         return "'" + value.toTime().toString(Qt::ISODate) + "'";
00552 
00553     return value.toString();
00554 }
00555 
00556 void ConstExpr::getQueryParameters(QuerySchemaParameterList& params)
00557 {
00558     Q_UNUSED(params);
00559 }
00560 
00561 bool ConstExpr::validate(ParseInfo& parseInfo)
00562 {
00563     if (!BaseExpr::validate(parseInfo))
00564         return false;
00565 
00566     return type()!=Field::InvalidType;
00567 }
00568 
00569 //=========================================
00570 QueryParameterExpr::QueryParameterExpr(const QString& message)
00571 : ConstExpr( QUERY_PARAMETER, message )
00572 , m_type(Field::Text)
00573 {
00574     m_cl = KexiDBExpr_QueryParameter;
00575 }
00576 
00577 QueryParameterExpr::QueryParameterExpr(const QueryParameterExpr& expr)
00578  : ConstExpr(expr)
00579  , m_type(expr.m_type)
00580 {
00581 }
00582 
00583 QueryParameterExpr::~QueryParameterExpr()
00584 {
00585 }
00586 
00587 QueryParameterExpr* QueryParameterExpr::copy() const
00588 {
00589     return new QueryParameterExpr(*this);
00590 }
00591 
00592 Field::Type QueryParameterExpr::type()
00593 {
00594     return m_type;
00595 }
00596 
00597 void QueryParameterExpr::setType(Field::Type type)
00598 {
00599     m_type = type;
00600 }
00601 
00602 QString QueryParameterExpr::debugString()
00603 {
00604     return QString("QueryParameterExpr('") + QString::fromLatin1("[%2]").arg(value.toString())
00605         + QString("',type=%1)").arg(Driver::defaultSQLTypeName(type()));
00606 }
00607 
00608 QString QueryParameterExpr::toString(QuerySchemaParameterValueListIterator* params)
00609 {
00610     return params ? params->getPreviousValueAsString(type()) : QString::fromLatin1("[%2]").arg(value.toString());
00611 }
00612 
00613 void QueryParameterExpr::getQueryParameters(QuerySchemaParameterList& params)
00614 {
00615     QuerySchemaParameter param;
00616     param.message = value.toString();
00617     param.type = type();
00618     params.append( param );
00619 }
00620 
00621 bool QueryParameterExpr::validate(ParseInfo& parseInfo)
00622 {
00623     Q_UNUSED(parseInfo);
00624     return type()!=Field::InvalidType;
00625 }
00626 
00627 //=========================================
00628 VariableExpr::VariableExpr(const QString& _name)
00629 : BaseExpr( 0/*undefined*/ )
00630 , name(_name)
00631 , field(0)
00632 , tablePositionForField(-1)
00633 , tableForQueryAsterisk(0)
00634 {
00635     m_cl = KexiDBExpr_Variable;
00636 }
00637 
00638 VariableExpr::VariableExpr(const VariableExpr& expr)
00639  : BaseExpr(expr)
00640  , name(expr.name)
00641  , field(expr.field)
00642  , tablePositionForField(expr.tablePositionForField)
00643  , tableForQueryAsterisk(expr.tableForQueryAsterisk)
00644 {
00645 }
00646 
00647 VariableExpr::~VariableExpr()
00648 {
00649 }
00650 
00651 VariableExpr* VariableExpr::copy() const
00652 {
00653     return new VariableExpr(*this);
00654 }
00655 
00656 QString VariableExpr::debugString()
00657 {
00658     return QString("VariableExpr(") + name
00659         + QString(",type=%1)").arg(field ? Driver::defaultSQLTypeName(type()) : QString("FIELD NOT DEFINED YET"));
00660 }
00661 
00662 QString VariableExpr::toString(QuerySchemaParameterValueListIterator* params)
00663 {
00664     Q_UNUSED(params);
00665     return name;
00666 }
00667 
00668 void VariableExpr::getQueryParameters(QuerySchemaParameterList& params)
00669 {
00670     Q_UNUSED(params);
00671 }
00672 
00674 Field::Type VariableExpr::type()
00675 {
00676     if (field)
00677         return field->type();
00678     
00679     //BTW, asterisks are not stored in VariableExpr outside of parser, so ok.
00680     return Field::InvalidType;
00681 }
00682 
00683 #define IMPL_ERROR(errmsg) parseInfo.errMsg = "Implementation error"; parseInfo.errDescr = errmsg
00684 
00685 bool VariableExpr::validate(ParseInfo& parseInfo)
00686 {
00687     if (!BaseExpr::validate(parseInfo))
00688         return false;
00689     field = 0;
00690     tablePositionForField = -1;
00691     tableForQueryAsterisk = 0;
00692 
00693 /* taken from parser's addColumn(): */
00694     KexiDBDbg << "checking variable name: " << name << endl;
00695     int dotPos = name.find('.');
00696     QString tableName, fieldName;
00697 //TODO: shall we also support db name?
00698     if (dotPos>0) {
00699         tableName = name.left(dotPos);
00700         fieldName = name.mid(dotPos+1);
00701     }
00702     if (tableName.isEmpty()) {//fieldname only
00703         fieldName = name;
00704         if (fieldName=="*") {
00705 //          querySchema->addAsterisk( new QueryAsterisk(querySchema) );
00706             return true;
00707         }
00708 
00709         //find first table that has this field
00710         Field *firstField = 0;
00711         foreach_list(TableSchema::ListIterator, it, *parseInfo.querySchema->tables()) {
00712             Field *f = it.current()->field(fieldName);
00713             if (f) {
00714                 if (!firstField) {
00715                     firstField = f;
00716                 }
00717                 else if (f->table()!=firstField->table()) {
00718                     //ambiguous field name
00719                     parseInfo.errMsg = i18n("Ambiguous field name");
00720                     parseInfo.errDescr = i18n("Both table \"%1\" and \"%2\" have defined \"%3\" field. "
00721                         "Use \"<tableName>.%4\" notation to specify table name.")
00722                         .arg(firstField->table()->name()).arg(f->table()->name())
00723                         .arg(fieldName).arg(fieldName);
00724                     return false;
00725                 }
00726             }
00727         }
00728         if (!firstField) {
00729             parseInfo.errMsg = i18n("Field not found");
00730             parseInfo.errDescr = i18n("Table containing \"%1\" field not found").arg(fieldName);
00731             return false;
00732         }
00733         //ok
00734         field = firstField; //store
00735 //      querySchema->addField(firstField);
00736         return true;
00737     }
00738 
00739     //table.fieldname or tableAlias.fieldname
00740     tableName = tableName.lower();
00741     TableSchema *ts = parseInfo.querySchema->table( tableName );
00742     if (ts) {//table.fieldname
00743         //check if "table" is covered by an alias
00744         const QValueList<int> tPositions = parseInfo.querySchema->tablePositions(tableName);
00745         QValueList<int>::ConstIterator it = tPositions.constBegin();
00746         QCString tableAlias;
00747         bool covered = true;
00748         for (; it!=tPositions.constEnd() && covered; ++it) {
00749             tableAlias = parseInfo.querySchema->tableAlias(*it);
00750             if (tableAlias.isEmpty() || tableAlias.lower()==tableName.latin1())
00751                 covered = false; //uncovered
00752             KexiDBDbg << " --" << "covered by " << tableAlias << " alias" << endl;
00753         }
00754         if (covered) {
00755             parseInfo.errMsg = i18n("Could not access the table directly using its name");
00756             parseInfo.errDescr = i18n("Table \"%1\" is covered by aliases. Instead of \"%2\", "
00757                 "you can write \"%3\"").arg(tableName)
00758                 .arg(tableName+"."+fieldName).arg(tableAlias+"."+fieldName.latin1());
00759             return false;
00760         }
00761     }
00762     
00763     int tablePosition = -1;
00764     if (!ts) {//try to find tableAlias
00765         tablePosition = parseInfo.querySchema->tablePositionForAlias( tableName.latin1() );
00766         if (tablePosition>=0) {
00767             ts = parseInfo.querySchema->tables()->at(tablePosition);
00768             if (ts) {
00769 //              KexiDBDbg << " --it's a tableAlias.name" << endl;
00770             }
00771         }
00772     }
00773 
00774     if (!ts) {
00775         parseInfo.errMsg = i18n("Table not found");
00776         parseInfo.errDescr = i18n("Unknown table \"%1\"").arg(tableName);
00777         return false;
00778     }
00779 
00780     QValueList<int> *positionsList = parseInfo.repeatedTablesAndAliases[ tableName ];
00781     if (!positionsList) { //for sanity
00782         IMPL_ERROR(tableName + "." + fieldName + ", !positionsList ");
00783         return false;
00784     }
00785 
00786     //it's a table.*
00787     if (fieldName=="*") {
00788         if (positionsList->count()>1) {
00789             parseInfo.errMsg = i18n("Ambiguous \"%1.*\" expression").arg(tableName);
00790             parseInfo.errDescr = i18n("More than one \"%1\" table or alias defined").arg(tableName);
00791             return false;
00792         }
00793         tableForQueryAsterisk = ts;
00794 //          querySchema->addAsterisk( new QueryAsterisk(querySchema, ts) );
00795         return true;
00796     }
00797 
00798 //  KexiDBDbg << " --it's a table.name" << endl;
00799     Field *realField = ts->field(fieldName);
00800     if (!realField) {
00801         parseInfo.errMsg = i18n("Field not found");
00802         parseInfo.errDescr = i18n("Table \"%1\" has no \"%2\" field")
00803             .arg(tableName).arg(fieldName);
00804         return false;
00805     }
00806 
00807     // check if table or alias is used twice and both have the same column
00808     // (so the column is ambiguous)
00809     int numberOfTheSameFields = 0;
00810     for (QValueList<int>::iterator it = positionsList->begin();
00811         it!=positionsList->end();++it)
00812     {
00813         TableSchema *otherTS = parseInfo.querySchema->tables()->at(*it);
00814         if (otherTS->field(fieldName))
00815             numberOfTheSameFields++;
00816         if (numberOfTheSameFields>1) {
00817             parseInfo.errMsg = i18n("Ambiguous \"%1.%2\" expression")
00818                 .arg(tableName).arg(fieldName);
00819             parseInfo.errDescr = i18n("More than one \"%1\" table or alias defined containing \"%2\" field")
00820                 .arg(tableName).arg(fieldName);
00821             return false;
00822         }
00823     }
00824     field = realField; //store
00825     tablePositionForField = tablePosition;
00826 //              querySchema->addField(realField, tablePosition);
00827 
00828     return true;
00829 }
00830 
00831 //=========================================
00832 static QValueList<QCString> FunctionExpr_builtIns;
00833 static const char* FunctionExpr_builtIns_[] = 
00834 {"SUM", "MIN", "MAX", "AVG", "COUNT", "STD", "STDDEV", "VARIANCE", 0 };
00835 
00836 QValueList<QCString> FunctionExpr::builtInAggregates()
00837 {
00838     if (FunctionExpr_builtIns.isEmpty()) {
00839         for (const char **p = FunctionExpr_builtIns_; *p; p++)
00840             FunctionExpr_builtIns << *p;
00841     }
00842     return FunctionExpr_builtIns;
00843 }
00844 
00845 FunctionExpr::FunctionExpr( const QString& _name, NArgExpr* args_ )
00846  : BaseExpr( 0/*undefined*/ )
00847  , name(_name)
00848  , args(args_)
00849 {
00850     if (isBuiltInAggregate(name.latin1()))
00851         m_cl = KexiDBExpr_Aggregation;
00852     else
00853         m_cl = KexiDBExpr_Function;
00854     if (args)
00855         args->setParent( this );
00856 }
00857 
00858 FunctionExpr::FunctionExpr( const FunctionExpr& expr )
00859  : BaseExpr( 0/*undefined*/ )
00860  , name(expr.name)
00861  , args(expr.args ? args->copy() : 0)
00862 {
00863     if (args)
00864         args->setParent( this );
00865 }
00866 
00867 FunctionExpr::~FunctionExpr()
00868 {
00869     delete args;
00870 }
00871 
00872 FunctionExpr* FunctionExpr::copy() const
00873 {
00874     return new FunctionExpr(*this);
00875 }
00876 
00877 QString FunctionExpr::debugString()
00878 {
00879     QString res;
00880     res.append( QString("FunctionExpr(") + name );
00881     if (args)
00882         res.append(QString(",") + args->debugString());
00883     res.append(QString(",type=%1)").arg(Driver::defaultSQLTypeName(type())));
00884     return res;
00885 }
00886 
00887 QString FunctionExpr::toString(QuerySchemaParameterValueListIterator* params)
00888 {
00889     return name + "(" + (args ? args->toString(params) : QString::null) + ")";
00890 }
00891 
00892 void FunctionExpr::getQueryParameters(QuerySchemaParameterList& params)
00893 {
00894     args->getQueryParameters(params);
00895 }
00896 
00897 Field::Type FunctionExpr::type()
00898 {
00899     //TODO
00900     return Field::InvalidType;
00901 }
00902 
00903 bool FunctionExpr::validate(ParseInfo& parseInfo)
00904 {
00905     if (!BaseExpr::validate(parseInfo))
00906         return false;
00907 
00908     return args ? args->validate(parseInfo) : true;
00909 }
00910 
00911 bool FunctionExpr::isBuiltInAggregate(const QCString& fname)
00912 {
00913     return builtInAggregates().find(fname.upper())!=FunctionExpr_builtIns.end();
00914 }
KDE Home | KDE Accessibility Home | Description of Access Keys