kexi

expression.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
3
4 Based on nexp.cpp : Parser module of Python-like language
5 (C) 2001 Jaroslaw Staniek, MIMUW (www.mimuw.edu.pl)
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "expression.h"
24#include "utils.h"
25#include "parser/sqlparser.h"
26#include "parser/parser_p.h"
27
28#include <ctype.h>
29
30#include <kdebug.h>
31#include <tdelocale.h>
32
33#include <tqdatetime.h>
34
35KEXI_DB_EXPORT TQString KexiDB::exprClassName(int c)
36{
37 if (c==KexiDBExpr_Unary)
38 return "Unary";
39 else if (c==KexiDBExpr_Arithm)
40 return "Arithm";
41 else if (c==KexiDBExpr_Logical)
42 return "Logical";
43 else if (c==KexiDBExpr_Relational)
44 return "Relational";
45 else if (c==KexiDBExpr_SpecialBinary)
46 return "SpecialBinary";
47 else if (c==KexiDBExpr_Const)
48 return "Const";
49 else if (c==KexiDBExpr_Variable)
50 return "Variable";
51 else if (c==KexiDBExpr_Function)
52 return "Function";
53 else if (c==KexiDBExpr_Aggregation)
54 return "Aggregation";
55 else if (c==KexiDBExpr_TableList)
56 return "TableList";
57 else if (c==KexiDBExpr_QueryParameter)
58 return "QueryParameter";
59
60 return "Unknown";
61}
62
63using namespace KexiDB;
64
65//=========================================
66
67BaseExpr::BaseExpr(int token)
68 : m_cl(KexiDBExpr_Unknown)
69 , m_par(0)
70 , m_token(token)
71{
72}
73
74BaseExpr::~BaseExpr()
75{
76}
77
78Field::Type BaseExpr::type()
79{
80 return Field::InvalidType;
81}
82
83TQString BaseExpr::debugString()
84{
85 return TQString("BaseExpr(%1,type=%1)").arg(m_token).arg(Driver::defaultSQLTypeName(type()));
86}
87
88bool BaseExpr::validate(ParseInfo& /*parseInfo*/)
89{
90 return true;
91}
92
93extern const char * const tname(int offset);
94#define safe_tname(token) ((token>=255 && token<=__LAST_TOKEN) ? tname(token-255) : "")
95
96TQString BaseExpr::tokenToDebugString(int token)
97{
98 if (token < 254) {
99 if (isprint(token))
100 return TQString(TQChar(uchar(token)));
101 else
102 return TQString::number(token);
103 }
104 return TQString(safe_tname(token));
105}
106
108{
109 if (m_token < 255 && isprint(m_token))
110 return tokenToDebugString();
111 return TQString();
112}
113
114NArgExpr* BaseExpr::toNArg() { return dynamic_cast<NArgExpr*>(this); }
115UnaryExpr* BaseExpr::toUnary() { return dynamic_cast<UnaryExpr*>(this); }
116BinaryExpr* BaseExpr::toBinary() { return dynamic_cast<BinaryExpr*>(this); }
117ConstExpr* BaseExpr::toConst() { return dynamic_cast<ConstExpr*>(this); }
118VariableExpr* BaseExpr::toVariable() { return dynamic_cast<VariableExpr*>(this); }
119FunctionExpr* BaseExpr::toFunction() { return dynamic_cast<FunctionExpr*>(this); }
120QueryParameterExpr* BaseExpr::toQueryParameter() { return dynamic_cast<QueryParameterExpr*>(this); }
121
122//=========================================
123
124NArgExpr::NArgExpr(int aClass, int token)
125 : BaseExpr(token)
126{
127 m_cl = aClass;
128 list.setAutoDelete(true);
129}
130
131NArgExpr::NArgExpr(const NArgExpr& expr)
132 : BaseExpr(expr)
133{
134 foreach_list (BaseExpr::ListIterator, it, expr.list)
135 add( it.current()->copy() );
136}
137
138NArgExpr::~NArgExpr()
139{
140}
141
142NArgExpr* NArgExpr::copy() const
143{
144 return new NArgExpr(*this);
145}
146
147TQString NArgExpr::debugString()
148{
149 TQString s = TQString("NArgExpr(")
150 + "class=" + exprClassName(m_cl);
151 for ( BaseExpr::ListIterator it(list); it.current(); ++it ) {
152 s+=", ";
153 s+=it.current()->debugString();
154 }
155 s+=")";
156 return s;
157}
158
160{
161 TQString s;
162 s.reserve(256);
163 foreach_list( BaseExpr::ListIterator, it, list) {
164 if (!s.isEmpty())
165 s+=", ";
166 s+=it.current()->toString(params);
167 }
168 return s;
169}
170
171void NArgExpr::getQueryParameters(QuerySchemaParameterList& params)
172{
173 foreach_list( BaseExpr::ListIterator, it, list)
174 it.current()->getQueryParameters(params);
175}
176
177BaseExpr* NArgExpr::arg(int nr)
178{
179 return list.at(nr);
180}
181
182void NArgExpr::add(BaseExpr *expr)
183{
184 list.append(expr);
185 expr->setParent(this);
186}
187
188void NArgExpr::prepend(BaseExpr *expr)
189{
190 list.prepend(expr);
191 expr->setParent(this);
192}
193
194int NArgExpr::args()
195{
196 return list.count();
197}
198
199bool NArgExpr::validate(ParseInfo& parseInfo)
200{
201 if (!BaseExpr::validate(parseInfo))
202 return false;
203
204 foreach_list(BaseExpr::ListIterator, it, list) {
205 if (!it.current()->validate(parseInfo))
206 return false;
207 }
208 return true;
209}
210
211//=========================================
212UnaryExpr::UnaryExpr(int token, BaseExpr *arg)
213 : BaseExpr(token)
214 , m_arg(arg)
215{
216 m_cl = KexiDBExpr_Unary;
217 if (m_arg)
218 m_arg->setParent(this);
219}
220
221UnaryExpr::UnaryExpr(const UnaryExpr& expr)
222 : BaseExpr(expr)
223 , m_arg( expr.m_arg ? expr.m_arg->copy() : 0 )
224{
225 if (m_arg)
226 m_arg->setParent(this);
227}
228
229UnaryExpr::~UnaryExpr()
230{
231 delete m_arg;
232}
233
234UnaryExpr* UnaryExpr::copy() const
235{
236 return new UnaryExpr(*this);
237}
238
239TQString UnaryExpr::debugString()
240{
241 return "UnaryExpr('"
242 + tokenToDebugString() + "', "
243 + (m_arg ? m_arg->debugString() : TQString("<NONE>"))
244 + TQString(",type=%1)").arg(Driver::defaultSQLTypeName(type()));
245}
246
248{
249 if (m_token=='(') //parentheses (special case)
250 return "(" + (m_arg ? m_arg->toString(params) : "<NULL>") + ")";
251 if (m_token < 255 && isprint(m_token))
252 return tokenToDebugString() + (m_arg ? m_arg->toString(params) : "<NULL>");
253 if (m_token==NOT)
254 return "NOT " + (m_arg ? m_arg->toString(params) : "<NULL>");
255 if (m_token==SQL_IS_NULL)
256 return (m_arg ? m_arg->toString(params) : "<NULL>") + " IS NULL";
257 if (m_token==SQL_IS_NOT_NULL)
258 return (m_arg ? m_arg->toString(params) : "<NULL>") + " IS NOT NULL";
259 return TQString("{INVALID_OPERATOR#%1} ").arg(m_token) + (m_arg ? m_arg->toString(params) : "<NULL>");
260}
261
262void UnaryExpr::getQueryParameters(QuerySchemaParameterList& params)
263{
264 if (m_arg)
265 m_arg->getQueryParameters(params);
266}
267
268Field::Type UnaryExpr::type()
269{
270 //NULL IS NOT NULL : BOOLEAN
271 //NULL IS NULL : BOOLEAN
272 switch (m_token) {
273 case SQL_IS_NULL:
274 case SQL_IS_NOT_NULL:
275 return Field::Boolean;
276 }
277 const Field::Type t = m_arg->type();
278 if (t==Field::Null)
279 return Field::Null;
280 if (m_token==NOT)
281 return Field::Boolean;
282
283 return t;
284}
285
286bool UnaryExpr::validate(ParseInfo& parseInfo)
287{
288 if (!BaseExpr::validate(parseInfo))
289 return false;
290
291 if (!m_arg->validate(parseInfo))
292 return false;
293
295
296 // update type
297 if (m_arg->toQueryParameter()) {
298 m_arg->toQueryParameter()->setType(type());
299 }
300
301 return true;
302#if 0
303 BaseExpr *n = l.at(0);
304
305 n->check();
306/*typ wyniku:
307 const bool dla "NOT <bool>" (negacja)
308 int dla "# <str>" (dlugosc stringu)
309 int dla "+/- <int>"
310 */
311 if (is(NOT) && n->nodeTypeIs(TYP_BOOL)) {
312 node_type=new NConstType(TYP_BOOL);
313 }
314 else if (is('#') && n->nodeTypeIs(TYP_STR)) {
315 node_type=new NConstType(TYP_INT);
316 }
317 else if ((is('+') || is('-')) && n->nodeTypeIs(TYP_INT)) {
318 node_type=new NConstType(TYP_INT);
319 }
320 else {
321 ERR("Niepoprawny argument typu '%s' dla operatora '%s'",
322 n->nodeTypeName(),is(NOT)?TQString("not"):TQChar(typ()));
323 }
324#endif
325}
326
327//=========================================
328BinaryExpr::BinaryExpr(int aClass, BaseExpr *left_expr, int token, BaseExpr *right_expr)
329 : BaseExpr(token)
330 , m_larg(left_expr)
331 , m_rarg(right_expr)
332{
333 m_cl = aClass;
334 if (m_larg)
335 m_larg->setParent(this);
336 if (m_rarg)
337 m_rarg->setParent(this);
338}
339
340BinaryExpr::BinaryExpr(const BinaryExpr& expr)
341 : BaseExpr(expr)
342 , m_larg( expr.m_larg ? expr.m_larg->copy() : 0 )
343 , m_rarg( expr.m_rarg ? expr.m_rarg->copy() : 0 )
344{
345}
346
347BinaryExpr::~BinaryExpr()
348{
349 delete m_larg;
350 delete m_rarg;
351}
352
353BinaryExpr* BinaryExpr::copy() const
354{
355 return new BinaryExpr(*this);
356}
357
358bool BinaryExpr::validate(ParseInfo& parseInfo)
359{
360 if (!BaseExpr::validate(parseInfo))
361 return false;
362
363 if (!m_larg->validate(parseInfo))
364 return false;
365 if (!m_rarg->validate(parseInfo))
366 return false;
367
369
370 //update type for query parameters
371 QueryParameterExpr * queryParameter = m_larg->toQueryParameter();
372 if (queryParameter)
373 queryParameter->setType(m_rarg->type());
374 queryParameter = m_rarg->toQueryParameter();
375 if (queryParameter)
376 queryParameter->setType(m_larg->type());
377
378 return true;
379}
380
381Field::Type BinaryExpr::type()
382{
383 const Field::Type lt = m_larg->type(), rt = m_rarg->type();
384 if (lt==Field::InvalidType || rt == Field::InvalidType)
385 return Field::InvalidType;
386 if (lt==Field::Null || rt == Field::Null) {
387 if (m_token!=OR) //note that NULL OR something != NULL
388 return Field::Null;
389 }
390
391 switch (m_token) {
392 case BITWISE_SHIFT_RIGHT:
393 case BITWISE_SHIFT_LEFT:
394 case CONCATENATION:
395 return lt;
396 }
397
398 const bool ltInt = Field::isIntegerType(lt);
399 const bool rtInt = Field::isIntegerType(rt);
400 if (ltInt && rtInt)
401 return KexiDB::maximumForIntegerTypes(lt, rt);
402
403 if (Field::isFPNumericType(lt) && (rtInt || lt==rt))
404 return lt;
405 if (Field::isFPNumericType(rt) && (ltInt || lt==rt))
406 return rt;
407
408 return Field::Boolean;
409}
410
411TQString BinaryExpr::debugString()
412{
413 return TQString("BinaryExpr(")
414 + "class=" + exprClassName(m_cl)
415 + "," + (m_larg ? m_larg->debugString() : TQString("<NONE>"))
416 + ",'" + tokenToDebugString() + "',"
417 + (m_rarg ? m_rarg->debugString() : TQString("<NONE>"))
418 + TQString(",type=%1)").arg(Driver::defaultSQLTypeName(type()));
419}
420
422{
423 if (m_token < 255 && isprint(m_token))
424 return tokenToDebugString();
425 // other arithmetic operations: << >>
426 switch (m_token) {
427 case BITWISE_SHIFT_RIGHT: return ">>";
428 case BITWISE_SHIFT_LEFT: return "<<";
429 // other relational operations: <= >= <> (or !=) LIKE IN
430 case NOT_EQUAL: return "<>";
431 case NOT_EQUAL2: return "!=";
432 case LESS_OR_EQUAL: return "<=";
433 case GREATER_OR_EQUAL: return ">=";
434 case LIKE: return "LIKE";
435 case SQL_IN: return "IN";
436 // other logical operations: OR (or ||) AND (or &&) XOR
437 case SIMILAR_TO: return "SIMILAR TO";
438 case NOT_SIMILAR_TO: return "NOT SIMILAR TO";
439 case OR: return "OR";
440 case AND: return "AND";
441 case XOR: return "XOR";
442 // other string operations: || (as CONCATENATION)
443 case CONCATENATION: return "||";
444 // SpecialBinary "pseudo operators":
445 /* not handled here */
446 default:;
447 }
448 return TQString("{INVALID_BINARY_OPERATOR#%1} ").arg(m_token);
449}
450
452{
453#define INFIX(a) \
454 (m_larg ? m_larg->toString(params) : "<NULL>") + " " + a + " " + (m_rarg ? m_rarg->toString(params) : "<NULL>")
455 return INFIX(tokenToString());
456}
457
458void BinaryExpr::getQueryParameters(QuerySchemaParameterList& params)
459{
460 if (m_larg)
461 m_larg->getQueryParameters(params);
462 if (m_rarg)
463 m_rarg->getQueryParameters(params);
464}
465
466//=========================================
467ConstExpr::ConstExpr( int token, const TQVariant& val)
468: BaseExpr( token )
469, value(val)
470{
471 m_cl = KexiDBExpr_Const;
472}
473
474ConstExpr::ConstExpr(const ConstExpr& expr)
475 : BaseExpr(expr)
476 , value(expr.value)
477{
478}
479
480ConstExpr::~ConstExpr()
481{
482}
483
484ConstExpr* ConstExpr::copy() const
485{
486 return new ConstExpr(*this);
487}
488
489Field::Type ConstExpr::type()
490{
491 if (m_token==SQL_NULL)
492 return Field::Null;
493 else if (m_token==INTEGER_CONST) {
494//TODO ok?
495//TODO: add sign info?
496 if (value.type() == TQVariant::Int || value.type() == TQVariant::UInt) {
497 TQ_LLONG v = value.toInt();
498 if (v <= 0xff && v > -0x80)
499 return Field::Byte;
500 if (v <= 0xffff && v > -0x8000)
501 return Field::ShortInteger;
502 return Field::Integer;
503 }
504 return Field::BigInteger;
505 }
506 else if (m_token==CHARACTER_STRING_LITERAL) {
507//TODO: Field::defaultTextLength() is hardcoded now!
508 if (value.toString().length() > Field::defaultTextLength())
509 return Field::LongText;
510 else
511 return Field::Text;
512 }
513 else if (m_token==REAL_CONST)
514 return Field::Double;
515 else if (m_token==DATE_CONST)
516 return Field::Date;
517 else if (m_token==DATETIME_CONST)
518 return Field::DateTime;
519 else if (m_token==TIME_CONST)
520 return Field::Time;
521
522 return Field::InvalidType;
523}
524
525TQString ConstExpr::debugString()
526{
527 return TQString("ConstExpr('") + tokenToDebugString() +"'," + toString()
528 + TQString(",type=%1)").arg(Driver::defaultSQLTypeName(type()));
529}
530
532{
533 Q_UNUSED(params);
534 if (m_token==SQL_NULL)
535 return "NULL";
536 else if (m_token==CHARACTER_STRING_LITERAL)
537//TODO: better escaping!
538 return "'" + value.toString() + "'";
539 else if (m_token==REAL_CONST)
540 return TQString::number(value.toPoint().x())+"."+TQString::number(value.toPoint().y());
541 else if (m_token==DATE_CONST)
542 return "'" + value.toDate().toString(TQt::ISODate) + "'";
543 else if (m_token==DATETIME_CONST)
544 return "'" + value.toDateTime().date().toString(TQt::ISODate)
545 + " " + value.toDateTime().time().toString(TQt::ISODate) + "'";
546 else if (m_token==TIME_CONST)
547 return "'" + value.toTime().toString(TQt::ISODate) + "'";
548
549 return value.toString();
550}
551
552void ConstExpr::getQueryParameters(QuerySchemaParameterList& params)
553{
554 Q_UNUSED(params);
555}
556
557bool ConstExpr::validate(ParseInfo& parseInfo)
558{
559 if (!BaseExpr::validate(parseInfo))
560 return false;
561
562 return type()!=Field::InvalidType;
563}
564
565//=========================================
566QueryParameterExpr::QueryParameterExpr(const TQString& message)
567: ConstExpr( QUERY_PARAMETER, message )
568, m_type(Field::Text)
569{
570 m_cl = KexiDBExpr_QueryParameter;
571}
572
573QueryParameterExpr::QueryParameterExpr(const QueryParameterExpr& expr)
574 : ConstExpr(expr)
575 , m_type(expr.m_type)
576{
577}
578
579QueryParameterExpr::~QueryParameterExpr()
580{
581}
582
583QueryParameterExpr* QueryParameterExpr::copy() const
584{
585 return new QueryParameterExpr(*this);
586}
587
588Field::Type QueryParameterExpr::type()
589{
590 return m_type;
591}
592
594{
595 m_type = type;
596}
597
598TQString QueryParameterExpr::debugString()
599{
600 return TQString("QueryParameterExpr('") + TQString::fromLatin1("[%2]").arg(value.toString())
601 + TQString("',type=%1)").arg(Driver::defaultSQLTypeName(type()));
602}
603
605{
606 return params ? params->getPreviousValueAsString(type()) : TQString::fromLatin1("[%2]").arg(value.toString());
607}
608
609void QueryParameterExpr::getQueryParameters(QuerySchemaParameterList& params)
610{
612 param.message = value.toString();
613 param.type = type();
614 params.append( param );
615}
616
617bool QueryParameterExpr::validate(ParseInfo& parseInfo)
618{
619 Q_UNUSED(parseInfo);
620 return type()!=Field::InvalidType;
621}
622
623//=========================================
624VariableExpr::VariableExpr(const TQString& _name)
625: BaseExpr( 0/*undefined*/ )
626, name(_name)
627, field(0)
628, tablePositionForField(-1)
629, tableForQueryAsterisk(0)
630{
631 m_cl = KexiDBExpr_Variable;
632}
633
634VariableExpr::VariableExpr(const VariableExpr& expr)
635 : BaseExpr(expr)
636 , name(expr.name)
637 , field(expr.field)
638 , tablePositionForField(expr.tablePositionForField)
639 , tableForQueryAsterisk(expr.tableForQueryAsterisk)
640{
641}
642
643VariableExpr::~VariableExpr()
644{
645}
646
647VariableExpr* VariableExpr::copy() const
648{
649 return new VariableExpr(*this);
650}
651
652TQString VariableExpr::debugString()
653{
654 return TQString("VariableExpr(") + name
655 + TQString(",type=%1)").arg(field ? Driver::defaultSQLTypeName(type()) : TQString("FIELD NOT DEFINED YET"));
656}
657
659{
660 Q_UNUSED(params);
661 return name;
662}
663
664void VariableExpr::getQueryParameters(QuerySchemaParameterList& params)
665{
666 Q_UNUSED(params);
667}
668
671{
672 if (field)
673 return field->type();
674
675 //BTW, asterisks are not stored in VariableExpr outside of parser, so ok.
676 return Field::InvalidType;
677}
678
679#define IMPL_ERROR(errmsg) parseInfo.errMsg = "Implementation error"; parseInfo.errDescr = errmsg
680
681bool VariableExpr::validate(ParseInfo& parseInfo)
682{
683 if (!BaseExpr::validate(parseInfo))
684 return false;
685 field = 0;
686 tablePositionForField = -1;
688
689/* taken from parser's addColumn(): */
690 KexiDBDbg << "checking variable name: " << name << endl;
691 int dotPos = name.find('.');
692 TQString tableName, fieldName;
693//TODO: shall we also support db name?
694 if (dotPos>0) {
695 tableName = name.left(dotPos);
696 fieldName = name.mid(dotPos+1);
697 }
698 if (tableName.isEmpty()) {//fieldname only
699 fieldName = name;
700 if (fieldName=="*") {
701// querySchema->addAsterisk( new QueryAsterisk(querySchema) );
702 return true;
703 }
704
705 //find first table that has this field
706 Field *firstField = 0;
707 foreach_list(TableSchema::ListIterator, it, *parseInfo.querySchema->tables()) {
708 Field *f = it.current()->field(fieldName);
709 if (f) {
710 if (!firstField) {
711 firstField = f;
712 }
713 else if (f->table()!=firstField->table()) {
714 //ambiguous field name
715 parseInfo.errMsg = i18n("Ambiguous field name");
716 parseInfo.errDescr = i18n("Both table \"%1\" and \"%2\" have defined \"%3\" field. "
717 "Use \"<tableName>.%4\" notation to specify table name.")
718 .arg(firstField->table()->name()).arg(f->table()->name())
719 .arg(fieldName).arg(fieldName);
720 return false;
721 }
722 }
723 }
724 if (!firstField) {
725 parseInfo.errMsg = i18n("Field not found");
726 parseInfo.errDescr = i18n("Table containing \"%1\" field not found").arg(fieldName);
727 return false;
728 }
729 //ok
730 field = firstField; //store
731// querySchema->addField(firstField);
732 return true;
733 }
734
735 //table.fieldname or tableAlias.fieldname
736 tableName = tableName.lower();
737 TableSchema *ts = parseInfo.querySchema->table( tableName );
738 if (ts) {//table.fieldname
739 //check if "table" is covered by an alias
740 const TQValueList<int> tPositions = parseInfo.querySchema->tablePositions(tableName);
741 TQValueList<int>::ConstIterator it = tPositions.constBegin();
742 TQCString tableAlias;
743 bool covered = true;
744 for (; it!=tPositions.constEnd() && covered; ++it) {
745 tableAlias = parseInfo.querySchema->tableAlias(*it);
746 if (tableAlias.isEmpty() || tableAlias.lower()==tableName.latin1())
747 covered = false; //uncovered
748 KexiDBDbg << " --" << "covered by " << tableAlias << " alias" << endl;
749 }
750 if (covered) {
751 parseInfo.errMsg = i18n("Could not access the table directly using its name");
752 parseInfo.errDescr = i18n("Table \"%1\" is covered by aliases. Instead of \"%2\", "
753 "you can write \"%3\"").arg(tableName)
754 .arg(TQString(tableName+"."+fieldName)).arg(TQString(tableAlias+"."+fieldName.latin1()));
755 return false;
756 }
757 }
758
759 int tablePosition = -1;
760 if (!ts) {//try to find tableAlias
761 tablePosition = parseInfo.querySchema->tablePositionForAlias( tableName.latin1() );
762 if (tablePosition>=0) {
763 ts = parseInfo.querySchema->tables()->at(tablePosition);
764 if (ts) {
765// KexiDBDbg << " --it's a tableAlias.name" << endl;
766 }
767 }
768 }
769
770 if (!ts) {
771 parseInfo.errMsg = i18n("Table not found");
772 parseInfo.errDescr = i18n("Unknown table \"%1\"").arg(tableName);
773 return false;
774 }
775
776 TQValueList<int> *positionsList = parseInfo.repeatedTablesAndAliases[ tableName ];
777 if (!positionsList) { //for sanity
778 IMPL_ERROR(tableName + "." + fieldName + ", !positionsList ");
779 return false;
780 }
781
782 //it's a table.*
783 if (fieldName=="*") {
784 if (positionsList->count()>1) {
785 parseInfo.errMsg = i18n("Ambiguous \"%1.*\" expression").arg(tableName);
786 parseInfo.errDescr = i18n("More than one \"%1\" table or alias defined").arg(tableName);
787 return false;
788 }
790// querySchema->addAsterisk( new QueryAsterisk(querySchema, ts) );
791 return true;
792 }
793
794// KexiDBDbg << " --it's a table.name" << endl;
795 Field *realField = ts->field(fieldName);
796 if (!realField) {
797 parseInfo.errMsg = i18n("Field not found");
798 parseInfo.errDescr = i18n("Table \"%1\" has no \"%2\" field")
799 .arg(tableName).arg(fieldName);
800 return false;
801 }
802
803 // check if table or alias is used twice and both have the same column
804 // (so the column is ambiguous)
805 int numberOfTheSameFields = 0;
806 for (TQValueList<int>::iterator it = positionsList->begin();
807 it!=positionsList->end();++it)
808 {
809 TableSchema *otherTS = parseInfo.querySchema->tables()->at(*it);
810 if (otherTS->field(fieldName))
811 numberOfTheSameFields++;
812 if (numberOfTheSameFields>1) {
813 parseInfo.errMsg = i18n("Ambiguous \"%1.%2\" expression")
814 .arg(tableName).arg(fieldName);
815 parseInfo.errDescr = i18n("More than one \"%1\" table or alias defined containing \"%2\" field")
816 .arg(tableName).arg(fieldName);
817 return false;
818 }
819 }
820 field = realField; //store
821 tablePositionForField = tablePosition;
822// querySchema->addField(realField, tablePosition);
823
824 return true;
825}
826
827//=========================================
828static TQValueList<TQCString> FunctionExpr_builtIns;
829static const char* FunctionExpr_builtIns_[] =
830{"SUM", "MIN", "MAX", "AVG", "COUNT", "STD", "STDDEV", "VARIANCE", 0 };
831
832TQValueList<TQCString> FunctionExpr::builtInAggregates()
833{
834 if (FunctionExpr_builtIns.isEmpty()) {
835 for (const char **p = FunctionExpr_builtIns_; *p; p++)
836 FunctionExpr_builtIns << *p;
837 }
838 return FunctionExpr_builtIns;
839}
840
841FunctionExpr::FunctionExpr( const TQString& _name, NArgExpr* args_ )
842 : BaseExpr( 0/*undefined*/ )
843 , name(_name)
844 , args(args_)
845{
846 if (isBuiltInAggregate(name.latin1()))
847 m_cl = KexiDBExpr_Aggregation;
848 else
849 m_cl = KexiDBExpr_Function;
850 if (args)
851 args->setParent( this );
852}
853
854FunctionExpr::FunctionExpr( const FunctionExpr& expr )
855 : BaseExpr( 0/*undefined*/ )
856 , name(expr.name)
857 , args(expr.args ? args->copy() : 0)
858{
859 if (args)
860 args->setParent( this );
861}
862
863FunctionExpr::~FunctionExpr()
864{
865 delete args;
866}
867
868FunctionExpr* FunctionExpr::copy() const
869{
870 return new FunctionExpr(*this);
871}
872
873TQString FunctionExpr::debugString()
874{
875 TQString res;
876 res.append( TQString("FunctionExpr(") + name );
877 if (args)
878 res.append(TQString(",") + args->debugString());
879 res.append(TQString(",type=%1)").arg(Driver::defaultSQLTypeName(type())));
880 return res;
881}
882
884{
885 return name + "(" + (args ? args->toString(params) : TQString()) + ")";
886}
887
888void FunctionExpr::getQueryParameters(QuerySchemaParameterList& params)
889{
890 args->getQueryParameters(params);
891}
892
893Field::Type FunctionExpr::type()
894{
895 //TODO
896 return Field::InvalidType;
897}
898
899bool FunctionExpr::validate(ParseInfo& parseInfo)
900{
901 if (!BaseExpr::validate(parseInfo))
902 return false;
903
904 return args ? args->validate(parseInfo) : true;
905}
906
907bool FunctionExpr::isBuiltInAggregate(const TQCString& fname)
908{
909 return builtInAggregates().find(fname.upper())!=FunctionExpr_builtIns.end();
910}
A base class for all expressions.
Definition expression.h:67
NArgExpr * toNArg()
virtual BaseExpr * copy() const =0
virtual TQString tokenToString()
TQString tokenToDebugString()
Definition expression.h:104
virtual void getQueryParameters(QuerySchemaParameterList &params)
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual BinaryExpr * copy() const
virtual TQString tokenToString()
virtual bool validate(ParseInfo &parseInfo)
virtual void getQueryParameters(QuerySchemaParameterList &params)
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual ConstExpr * copy() const
static TQString defaultSQLTypeName(int id_t)
Definition driver.cpp:206
Field * field(uint id)
Definition fieldlist.h:76
Meta-data for a field.
Definition field.h:73
@ ShortInteger
Definition field.h:86
@ InvalidType
Definition field.h:84
bool isFPNumericType() const
Definition field.h:266
bool isIntegerType() const
Definition field.h:259
virtual TableSchema * table() const
Definition field.cpp:300
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual void getQueryParameters(QuerySchemaParameterList &params)
virtual FunctionExpr * copy() const
A base class N-argument operation.
Definition expression.h:130
virtual void getQueryParameters(QuerySchemaParameterList &params)
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual NArgExpr * copy() const
virtual QueryParameterExpr * copy() const
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual void getQueryParameters(QuerySchemaParameterList &params)
void setType(Field::Type type)
An iteratof for a list of values of query schema parameters providing Allows to iterate over paramete...
A single parameter of a query schema.
Field::Type type
A datatype of the parameter.
TQString message
A user-visible message that will be displayed to ask for value of the parameter.
TQPtrListIterator< TableSchema > ListIterator
Iterator for tables list.
Definition tableschema.h:46
An unary argument operation: + - NOT (or !) ~ "IS NULL" "IS NOT NULL".
Definition expression.h:150
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual UnaryExpr * copy() const
virtual void getQueryParameters(QuerySchemaParameterList &params)
virtual bool validate(ParseInfo &parseInfo)
Variables like fieldname or tablename.fieldname.
Definition expression.h:245
TableSchema * tableForQueryAsterisk
Definition expression.h:282
virtual void getQueryParameters(QuerySchemaParameterList &params)
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)
virtual VariableExpr * copy() const
virtual Field::Type type()
We're assuming it's called after VariableExpr::validate().
virtual bool validate(ParseInfo &parseInfo)
High-level database connectivity library with database backend drivers.
KEXI_DB_EXPORT Field::Type maximumForIntegerTypes(Field::Type t1, Field::Type t2)
KEXI_DB_EXPORT TQString exprClassName(int c)
Custom tokens are not used in parser but used as extension in expression classes.