~smartboyhw/ubuntu/raring/calligra/2.6.0-0ubuntu1

« back to all changes in this revision

Viewing changes to libs/db/expression.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2012-10-23 21:09:16 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20121023210916-m82w6zxnxhaxz7va
Tags: 1:2.5.90-0ubuntu1
* New upstream alpha release (LP: #1070436)
  - Add libkactivities-dev and libopenimageio-dev to build-depends
  - Add kubuntu_build_calligraactive.diff to build calligraactive by default
  - Add package for calligraauthor and move files that are shared between
    calligrawords and calligraauthor to calligrawords-common
* Document the patches
* Remove numbers from patches so they follow the same naming scheme as
  the rest of our patches.
* calligra-data breaks replaces krita-data (<< 1:2.5.3) (LP: #1071686)

Show diffs side-by-side

added added

removed removed

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