[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kdb] /: Make <SELECT "a" + "b"> SQL queries work and fix <SELECT "a" || "b">
From: Jaroslaw Staniek <staniek () kde ! org>
Date: 2016-02-29 23:21:25
Message-ID: E1aaX81-0005Dj-2C () scm ! kde ! org
[Download RAW message or body]
Git commit f19ae68c17822b33097119974b2ee01c0b93c534 by Jaroslaw Staniek.
Committed on 29/02/2016 at 23:16.
Pushed by staniek into branch 'master'.
Make <SELECT "a" + "b"> SQL queries work and fix <SELECT "a" || "b">
Summary:
- port from calligra.git
- <SELECT "a" + "b"> parses in Kexi>=2.9.7 but results in invalid (boolean) \
type/value
- for convenience, if either argument is of text type, operator "+" is now assumed to \
be identical to operator ||
- also fix SELECT "a" || "b" for MySQL (using CONCAT() is needed)
- add autotests and parser tests
https://phabricator.kde.org/T677
BUG:358636
FIXED-IN:2.9.11
Test Plan:
Try test queries from the project attached at \
https://bugs.kde.org/show_bug.cgi?id=358636. Try other queries that use text columns \
instead of string constants.
Differential Revision: https://phabricator.kde.org/D867
(from calligra.git)
M +9 -2 autotests/ExpressionsTest.cpp
M +11 -0 autotests/parser/data/statements.txt
M +9 -1 src/KDbDriver.cpp
M +12 -1 src/KDbDriver.h
M +9 -1 src/drivers/mysql/MysqlDriver.cpp
M +7 -1 src/drivers/mysql/MysqlDriver.h
M +17 -2 src/expression/KDbBinaryExpression.cpp
M +1 -0 src/expression/KDbExpression.h
http://commits.kde.org/kdb/f19ae68c17822b33097119974b2ee01c0b93c534
diff --git a/autotests/ExpressionsTest.cpp b/autotests/ExpressionsTest.cpp
index 145dab1..aa61e91 100644
--- a/autotests/ExpressionsTest.cpp
+++ b/autotests/ExpressionsTest.cpp
@@ -1,5 +1,5 @@
/* This file is part of the KDE project
- Copyright (C) 2011-2015 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2011-2016 Jarosław Staniek <staniek@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -700,6 +700,7 @@ void ExpressionsTest::testBinaryExpressionCloning_data()
T(KDbToken::INTEGER_CONST, 3, KDbToken::AND, KDbToken::INTEGER_CONST, 4, "3 AND \
4");
T(KDbToken::INTEGER_CONST, 3, KDbToken::XOR, KDbToken::INTEGER_CONST, 4, "3 XOR \
4");
T(KDbToken::CHARACTER_STRING_LITERAL, "AB", KDbToken::CONCATENATION, \
KDbToken::CHARACTER_STRING_LITERAL, "CD", "'AB' || 'CD'"); + \
T(KDbToken::CHARACTER_STRING_LITERAL, "AB", '+', KDbToken::CHARACTER_STRING_LITERAL, \
"CD", "'AB' + 'CD'"); #undef T
}
@@ -1299,12 +1300,18 @@ void ExpressionsTest::testBinaryExpressionValidate_data()
T(KDbToken::REAL_CONST, 30.2, KDbToken::XOR, KDbToken::REAL_CONST, 20, \
KDbField::InvalidType); // string
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", KDbToken::CONCATENATION, \
KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Text); + \
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', KDbToken::CHARACTER_STRING_LITERAL, \
"cd", KDbField::Text); +
T(KDbToken::SQL_NULL, QVariant(), KDbToken::CONCATENATION, \
KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Null); + T(KDbToken::SQL_NULL, \
QVariant(), '+', KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Null); +
T(KDbToken::INTEGER_CONST, 50, KDbToken::CONCATENATION, KDbToken::INTEGER_CONST, \
20, KDbField::InvalidType);
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", KDbToken::CONCATENATION, \
KDbToken::INTEGER_CONST, 20, KDbField::InvalidType); + \
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', KDbToken::INTEGER_CONST, 20, \
KDbField::InvalidType); +
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", KDbToken::GREATER_OR_EQUAL, \
KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Boolean);
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '<', KDbToken::INTEGER_CONST, 3, \
KDbField::InvalidType);
- T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', \
KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::InvalidType); + \
T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', KDbToken::CHARACTER_STRING_LITERAL, \
"cd", KDbField::Text);
T(KDbToken::CHARACTER_STRING_LITERAL, "A", KDbToken::OR, KDbToken::REAL_CONST, \
20, KDbField::InvalidType);
T(KDbToken::CHARACTER_STRING_LITERAL, "A", KDbToken::AND, KDbToken::REAL_CONST, \
20, KDbField::InvalidType);
T(KDbToken::CHARACTER_STRING_LITERAL, "A", KDbToken::XOR, KDbToken::REAL_CONST, \
20, KDbField::InvalidType);
diff --git a/autotests/parser/data/statements.txt \
b/autotests/parser/data/statements.txt index fc0c3e1..95648c2 100644
--- a/autotests/parser/data/statements.txt
+++ b/autotests/parser/data/statements.txt
@@ -92,6 +92,17 @@ select 'ABC' LIKE 'A%';
select 3 SIMILAR TO 4;
select 3 NOT SIMILAR TO 4;
select 'AB' || 'CD';
+select 'AB' || 'CD' || 'EF';
+select 'AB' + 'CD' || 'EF' + 'GH' || '';
+select NULL || NULL;
+select NULL || 'AB';
+select 'AB' + NULL;
+-- ERROR: ||
+select 'AB' || 1;
+select 'AB' + 1;
+select 7 || 'AB';
+select 7 + 'AB';
+select 7 || 1;
-- ERROR: **
select 1**2;
-- ERROR: * or / are not unary operators
diff --git a/src/KDbDriver.cpp b/src/KDbDriver.cpp
index 8752585..efd460d 100644
--- a/src/KDbDriver.cpp
+++ b/src/KDbDriver.cpp
@@ -1,5 +1,5 @@
/* This file is part of the KDE project
- Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -356,6 +356,14 @@ KDbEscapedString KDbDriver::unicodeFunctionToString(
return KDbFunctionExpression::toString(QLatin1String("UNICODE"), this, args, \
params, callStack); }
+KDbEscapedString KDbDriver::concatenateFunctionToString(const KDbBinaryExpression \
&args, + \
KDbQuerySchemaParameterValueListIterator* params, + \
KDb::ExpressionCallStack* callStack) const +{
+ return args.left().toString(this, params, callStack) + KDbEscapedString("||")
+ + args.right().toString(this, params, callStack);
+}
+
//---------------
Q_GLOBAL_STATIC_WITH_ARGS(
diff --git a/src/KDbDriver.h b/src/KDbDriver.h
index 540e9cc..5b0b286 100644
--- a/src/KDbDriver.h
+++ b/src/KDbDriver.h
@@ -1,5 +1,5 @@
/* This file is part of the KDE project
- Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -40,6 +40,7 @@ class KDbConnectionOptions;
class KDbDriverManager;
class KDbDriverBehaviour;
class KDbDriverMetaData;
+class KDbBinaryExpression;
class KDbNArgExpression;
class KDbQuerySchemaParameterValueListIterator;
class DriverPrivate;
@@ -280,6 +281,16 @@ public:
\
KDbQuerySchemaParameterValueListIterator* params,
KDb::ExpressionCallStack* callStack) \
const;
+ //! Generates native (driver-specific) function call for concatenation of two \
strings. + //! Default implementation USES infix "||" operator.
+ //! Special case is for MYSQL (CONCAT()).
+ //! @todo API supporting KDbNArgExpression would be useful so instead of a||b||c \
can be + //! expressed as CONCAT(a,b,c) instead of CONCAT(CONCAT(a,b),c).
+ //! This requires changes to the KDbSQL parser.
+ KDbEscapedString concatenateFunctionToString(const KDbBinaryExpression &args,
+ \
KDbQuerySchemaParameterValueListIterator* params, + \
KDb::ExpressionCallStack* callStack) const; +
protected:
/*! Used by KDbDriverManager.
Note for driver developers: Reimplement this.
diff --git a/src/drivers/mysql/MysqlDriver.cpp b/src/drivers/mysql/MysqlDriver.cpp
index 70403a5..c6344ef 100644
--- a/src/drivers/mysql/MysqlDriver.cpp
+++ b/src/drivers/mysql/MysqlDriver.cpp
@@ -2,7 +2,7 @@
Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org>
- Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -221,4 +221,12 @@ KDbEscapedString MysqlDriver::unicodeFunctionToString(
.arg(args.arg(0).toString(this, params, callStack));
}
+KDbEscapedString MysqlDriver::concatenateFunctionToString(const KDbBinaryExpression \
&args, + \
KDbQuerySchemaParameterValueListIterator* params, + \
KDb::ExpressionCallStack* callStack) const +{
+ return KDbEscapedString("CONCAT(%1, %2)").arg(args.left().toString(this, params, \
callStack)) + \
.arg(args.right().toString(this, params, callStack)); +}
+
#include "MysqlDriver.moc"
diff --git a/src/drivers/mysql/MysqlDriver.h b/src/drivers/mysql/MysqlDriver.h
index bf86c72..a5d1530 100644
--- a/src/drivers/mysql/MysqlDriver.h
+++ b/src/drivers/mysql/MysqlDriver.h
@@ -2,7 +2,7 @@
Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org>
- Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -77,6 +77,12 @@ public:
\
KDbQuerySchemaParameterValueListIterator* params,
KDb::ExpressionCallStack* callStack) \
const;
+ //! Generates native (driver-specific) function call for concatenation of two \
strings. + //! Uses CONCAT().
+ KDbEscapedString concatenateFunctionToString(const KDbBinaryExpression &args,
+ \
KDbQuerySchemaParameterValueListIterator* params, + \
KDb::ExpressionCallStack* callStack) const; +
protected:
virtual QString drv_escapeIdentifier(const QString& str) const;
virtual QByteArray drv_escapeIdentifier(const QByteArray& str) const;
diff --git a/src/expression/KDbBinaryExpression.cpp \
b/src/expression/KDbBinaryExpression.cpp index 18ff7e0..5515861 100644
--- a/src/expression/KDbBinaryExpression.cpp
+++ b/src/expression/KDbBinaryExpression.cpp
@@ -1,5 +1,5 @@
/* This file is part of the KDE project
- Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
+ Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
Based on nexp.cpp : Parser module of Python-like language
(C) 2001 Jarosław Staniek, MIMUW (www.mimuw.edu.pl)
@@ -139,6 +139,7 @@ KDbField::Type \
KDbBinaryExpressionData::typeInternal(KDb::ExpressionCallStack* c return \
KDbField::Null; }
return (ltBool && rtBool) ? KDbField::Boolean : KDbField::InvalidType;
+ case '+':
case CONCATENATION:
if (lt == KDbField::Text && rt == KDbField::Text) {
return KDbField::Text;
@@ -150,8 +151,10 @@ KDbField::Type \
KDbBinaryExpressionData::typeInternal(KDb::ExpressionCallStack* c || (rtText && \
ltNull)) {
return KDbField::Null;
+ } else if (token.value() == CONCATENATION) {
+ return KDbField::InvalidType;
}
- return KDbField::InvalidType;
+ break; // '+' can still be handled below for non-text types
default:;
}
@@ -244,6 +247,18 @@ KDbEscapedString KDbBinaryExpressionData::toStringInternal(
KDbQuerySchemaParameterValueListIterator* \
params,
KDb::ExpressionCallStack* callStack) const
{
+ switch (token.value()) {
+ case '+':
+ case CONCATENATION: {
+ if (driver && KDbField::isTextType(type())) {
+ const KDbBinaryExpression \
binaryExpr(const_cast<KDbBinaryExpressionData*>(this)); + return \
driver->concatenateFunctionToString(binaryExpr, params, callStack); + }
+ break;
+ }
+ default:;
+ }
+
#define INFIX(a) \
(left().constData() ? left()->toString(driver, params, callStack) : \
KDbEscapedString("<NULL>")) \
+ " " + a + " " + (right().constData() ? right()->toString(driver, params, \
callStack) : KDbEscapedString("<NULL>"))
diff --git a/src/expression/KDbExpression.h b/src/expression/KDbExpression.h
index 11a5e88..9621123 100644
--- a/src/expression/KDbExpression.h
+++ b/src/expression/KDbExpression.h
@@ -369,6 +369,7 @@ protected:
explicit KDbBinaryExpression(const ExplicitlySharedExpressionDataPointer &ptr);
friend class KDbExpression;
+ friend class KDbBinaryExpressionData;
};
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic