From 0c206ff42843558f13d17d78f112913d27f8a91b Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 27 Feb 2018 02:55:05 +0200 Subject: [PATCH] MXS-1688 Handle ...INTERVAL N "INTERVAL N " is now handled as an expression in itself and as asuch will cause both statements such as "SELECT '2008-12-31 23:59:59' + INTERVAL 1 SECOND;" and "select id from db2.t1 where DATE_ADD("2017-06-15", INTERVAL 10 DAY) < "2017-06-15";" to be handled correctly. The compare test program contains some heuristic checking, as the the embedded parser will in all cases report date manipulation as the use of the add_date_interval() function. --- .../qc_sqlite/sqlite-src-3110100/src/parse.y | 4 +- query_classifier/test/compare.cc | 60 ++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y index f3f7e0007..fad997933 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y @@ -1948,10 +1948,10 @@ expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y). expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} %ifdef MAXSCALE -expr(A) ::= expr(X) PLUS|MINUS INTERVAL INTEGER id. { +expr(A) ::= INTERVAL INTEGER(X) id. { // Here we could check that id is one of MICROSECOND, SECOND, MINUTE // HOUR, DAY, WEEK, etc. - A=X; + spanExpr(&A, pParse, @X, &X); } %endif expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y). diff --git a/query_classifier/test/compare.cc b/query_classifier/test/compare.cc index 7b6fc611e..35185a0fd 100644 --- a/query_classifier/test/compare.cc +++ b/query_classifier/test/compare.cc @@ -1069,6 +1069,11 @@ public: return rv; } + const std::string& name() const + { + return m_name; + } + void print(ostream& out) const { out << m_name; @@ -1118,6 +1123,19 @@ bool operator == (const QcFunctionInfo& lhs, const QcFunctionInfo& rhs) return lhs.eq(rhs); } +void collect_missing_function_names(const std::set& one, + const std::set& other, + std::set* pNames) +{ + for (std::set::const_iterator i = one.begin(); i != one.end(); ++i) + { + if (other.count(*i) == 0) + { + pNames->insert(i->name()); + } + } +} + bool compare_get_function_info(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1, QUERY_CLASSIFIER* pClassifier2, GWBUF* pCopy2) { @@ -1151,7 +1169,47 @@ bool compare_get_function_info(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1, } else { - ss << "ERR: " << f1 << " != " << f2; + std::set names1; + collect_missing_function_names(f1, f2, &names1); + + std::set names2; + collect_missing_function_names(f2, f1, &names2); + + bool real_error = false; + + // We assume that names1 are from the qc_mysqlembedded and names2 from qc_sqlite. + // The embedded parser reports all date_add(), adddate(), date_sub() and subdate() + // functions as date_add_interval(). Further, all "DATE + INTERVAL ..." cases become + // use of date_add_interval() functions. + for (std::set::iterator i = names1.begin(); i != names1.end(); ++i) + { + if (*i == "date_add_interval") + { + if ((names2.count("date_add") == 0) && + (names2.count("adddate") == 0) && + (names2.count("date_sub") == 0) && + (names2.count("subdate") == 0) && + (names2.count("+") == 0) && + (names2.count("-") == 0)) + { + real_error = true; + } + } + else + { + real_error = true; + } + } + + if (real_error) + { + ss << "ERR: " << f1 << " != " << f2; + } + else + { + ss << "Ok : " << f1 << " != " << f2; + success = true; + } } report(success, ss.str());