From e99db9c21298ad56fc07333a408006aec2da1e43 Mon Sep 17 00:00:00 2001 From: Sergey Zefirov <72864488+mariadb-SergeyZefirov@users.noreply.github.com> Date: Wed, 5 Mar 2025 10:36:05 +0300 Subject: [PATCH] fix(plugin): MCOL-4942 No-table-SELECT now can return empty set (#3415) The query like "SELECT 1 WHERE 1=0" was returning a row despite unsatisfiable condition in WHERE. Now it returns an empty set. --- dbcon/joblist/jlf_tuplejoblist.cpp | 54 +++++++++---------- dbcon/joblist/tupleconstantstep.cpp | 11 +++- dbcon/joblist/tupleconstantstep.h | 1 + ...MCOL-4942-constant-select-empty-set.result | 22 ++++++++ .../MCOL-4942-constant-select-empty-set.test | 40 ++++++++++++++ utils/loggingcpp/exceptclasses.h | 18 +++++++ 6 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.result create mode 100644 mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.test diff --git a/dbcon/joblist/jlf_tuplejoblist.cpp b/dbcon/joblist/jlf_tuplejoblist.cpp index 0413a8bae..866deed85 100644 --- a/dbcon/joblist/jlf_tuplejoblist.cpp +++ b/dbcon/joblist/jlf_tuplejoblist.cpp @@ -4520,33 +4520,6 @@ void associateTupleJobSteps(JobStepVector& querySteps, JobStepVector& projectSte cout << endl; } - // @bug 2771, handle no table select query - if (jobInfo.tableList.empty()) - { - makeNoTableJobStep(querySteps, projectSteps, deliverySteps, jobInfo); - return; - } - - // Create a step vector for each table in the from clause. - TableInfoMap tableInfoMap; - - for (uint64_t i = 0; i < jobInfo.tableList.size(); i++) - { - uint32_t tableUid = jobInfo.tableList[i]; - tableInfoMap[tableUid] = TableInfo(); - tableInfoMap[tableUid].fTableOid = jobInfo.keyInfo->tupleKeyVec[tableUid].fId; - tableInfoMap[tableUid].fName = jobInfo.keyInfo->keyName[tableUid]; - tableInfoMap[tableUid].fAlias = jobInfo.keyInfo->tupleKeyVec[tableUid].fTable; - tableInfoMap[tableUid].fView = jobInfo.keyInfo->tupleKeyVec[tableUid].fView; - tableInfoMap[tableUid].fSchema = jobInfo.keyInfo->tupleKeyVec[tableUid].fSchema; - tableInfoMap[tableUid].fSubId = jobInfo.keyInfo->tupleKeyVec[tableUid].fSubId; - tableInfoMap[tableUid].fColsInColMap = jobInfo.columnMap[tableUid]; - } - - // Set of the columns being projected. - for (auto i = jobInfo.pjColList.begin(); i != jobInfo.pjColList.end(); i++) - jobInfo.returnColSet.insert(i->key); - // Strip constantbooleanquerySteps for (uint64_t i = 0; i < querySteps.size();) { @@ -4582,6 +4555,33 @@ void associateTupleJobSteps(JobStepVector& querySteps, JobStepVector& projectSte } } + // @bug 2771, handle no table select query + if (jobInfo.tableList.empty()) + { + makeNoTableJobStep(querySteps, projectSteps, deliverySteps, jobInfo); + return; + } + + // Create a step vector for each table in the from clause. + TableInfoMap tableInfoMap; + + for (uint64_t i = 0; i < jobInfo.tableList.size(); i++) + { + uint32_t tableUid = jobInfo.tableList[i]; + tableInfoMap[tableUid] = TableInfo(); + tableInfoMap[tableUid].fTableOid = jobInfo.keyInfo->tupleKeyVec[tableUid].fId; + tableInfoMap[tableUid].fName = jobInfo.keyInfo->keyName[tableUid]; + tableInfoMap[tableUid].fAlias = jobInfo.keyInfo->tupleKeyVec[tableUid].fTable; + tableInfoMap[tableUid].fView = jobInfo.keyInfo->tupleKeyVec[tableUid].fView; + tableInfoMap[tableUid].fSchema = jobInfo.keyInfo->tupleKeyVec[tableUid].fSchema; + tableInfoMap[tableUid].fSubId = jobInfo.keyInfo->tupleKeyVec[tableUid].fSubId; + tableInfoMap[tableUid].fColsInColMap = jobInfo.columnMap[tableUid]; + } + + // Set of the columns being projected. + for (auto i = jobInfo.pjColList.begin(); i != jobInfo.pjColList.end(); i++) + jobInfo.returnColSet.insert(i->key); + // double check if the function join canditates are still there. JobStepVector steps = querySteps; diff --git a/dbcon/joblist/tupleconstantstep.cpp b/dbcon/joblist/tupleconstantstep.cpp index ce540ed0e..d55deb5dc 100644 --- a/dbcon/joblist/tupleconstantstep.cpp +++ b/dbcon/joblist/tupleconstantstep.cpp @@ -284,7 +284,9 @@ void TupleConstantStep::constructContanstRow(const JobInfo& jobInfo) void TupleConstantStep::run() { if (fInputJobStepAssociation.outSize() == 0) + { throw logic_error("No input data list for constant step."); + } fInputDL = fInputJobStepAssociation.outAt(0)->rowGroupDL(); @@ -585,7 +587,9 @@ void TupleConstantStep::formatMiniStats() } // class TupleConstantOnlyStep -TupleConstantOnlyStep::TupleConstantOnlyStep(const JobInfo& jobInfo) : TupleConstantStep(jobInfo) +TupleConstantOnlyStep::TupleConstantOnlyStep(const JobInfo& jobInfo) + : TupleConstantStep(jobInfo) + , fEmptySet(jobInfo.constantFalse) { // fExtendedInfo = "TCOS: "; } @@ -667,7 +671,10 @@ void TupleConstantOnlyStep::run() fillInConstants(); - fOutputDL->insert(rgDataOut); + if (!fEmptySet) + { + fOutputDL->insert(rgDataOut); + } } catch (...) { diff --git a/dbcon/joblist/tupleconstantstep.h b/dbcon/joblist/tupleconstantstep.h index 3f92470ab..44867057e 100644 --- a/dbcon/joblist/tupleconstantstep.h +++ b/dbcon/joblist/tupleconstantstep.h @@ -132,6 +132,7 @@ class TupleConstantOnlyStep : public TupleConstantStep uint32_t nextBand(messageqcpp::ByteStream& bs) override; protected: + bool fEmptySet; using TupleConstantStep::fillInConstants; void fillInConstants() override; }; diff --git a/mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.result b/mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.result new file mode 100644 index 000000000..9b2af1c22 --- /dev/null +++ b/mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.result @@ -0,0 +1,22 @@ +DROP DATABASE IF EXISTS MCOL4942; +CREATE DATABASE MCOL4942; +USE MCOL4942; +CREATE TABLE t1col (id INT) ENGINE=Columnstore; +SELECT * FROM +( +SELECT ID +FROM +( +SELECT 1 ID +FROM +t1col +) V +UNION ALL +SELECT ID +FROM +( +SELECT NULL ID WHERE 1111=2222 +) V +) U; +ID +DROP DATABASE MCOL4942; diff --git a/mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.test b/mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.test new file mode 100644 index 000000000..8e1c62aed --- /dev/null +++ b/mysql-test/columnstore/bugfixes/MCOL-4942-constant-select-empty-set.test @@ -0,0 +1,40 @@ +--disable_warnings +DROP DATABASE IF EXISTS MCOL4942; +--enable_warnings +CREATE DATABASE MCOL4942; +USE MCOL4942; +CREATE TABLE t1col (id INT) ENGINE=Columnstore; + +SELECT * FROM + +( + + SELECT ID + + FROM + + ( + + SELECT 1 ID + + FROM + + t1col + + ) V + + UNION ALL + + SELECT ID + + FROM + + ( + + SELECT NULL ID WHERE 1111=2222 + + ) V + +) U; + +DROP DATABASE MCOL4942; diff --git a/utils/loggingcpp/exceptclasses.h b/utils/loggingcpp/exceptclasses.h index 456436066..511c52aa7 100644 --- a/utils/loggingcpp/exceptclasses.h +++ b/utils/loggingcpp/exceptclasses.h @@ -283,6 +283,24 @@ class ProtocolError : public std::logic_error } \ } while (0) +#define idblog(x) \ + do \ + { \ + { \ + std::ostringstream os; \ + \ + os << __FILE__ << "@" << __LINE__ << ": \'" << x << "\'"; \ + std::cerr << os.str() << std::endl; \ + logging::MessageLog logger((logging::LoggingID())); \ + logging::Message message; \ + logging::Message::Args args; \ + \ + args.add(os.str()); \ + message.format(args); \ + logger.logErrorMessage(message); \ + } \ + } while (0) + #define idbassert_s(x, s) \ do \ { \