kexi

expression.cpp

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