#include "binder/binder.h"
#include "binder/expression/expression_util.h"
#include "binder/query/return_with_clause/bound_return_clause.h"
#include "binder/query/return_with_clause/bound_with_clause.h"
#include "common/exception/binder.h"
#include "parser/query/regular_query.h"
using namespace lbug::common;
using namespace lbug::parser;
namespace lbug {
namespace binder {
void validateUnionColumnsOfTheSameType(
const std::vector<NormalizedSingleQuery>& normalizedSingleQueries) {
if (normalizedSingleQueries.size() <= 1) {
return;
}
auto columns = normalizedSingleQueries[0].getStatementResult()->getColumns();
for (auto i = 1u; i < normalizedSingleQueries.size(); i++) {
auto otherColumns = normalizedSingleQueries[i].getStatementResult()->getColumns();
if (columns.size() != otherColumns.size()) {
throw BinderException("The number of columns to union/union all must be the same.");
}
for (auto j = 0u; j < columns.size(); j++) {
ExpressionUtil::validateDataType(*otherColumns[j], columns[j]->getDataType());
}
}
}
void validateIsAllUnionOrUnionAll(const BoundRegularQuery& regularQuery) {
auto unionAllExpressionCounter = 0u;
for (auto i = 0u; i < regularQuery.getNumSingleQueries() - 1; i++) {
unionAllExpressionCounter += regularQuery.getIsUnionAll(i);
}
if ((0 < unionAllExpressionCounter) &&
(unionAllExpressionCounter < regularQuery.getNumSingleQueries() - 1)) {
throw BinderException("Union and union all can not be used together.");
}
}
std::unique_ptr<BoundRegularQuery> Binder::bindQuery(const Statement& statement) {
auto& regularQuery = statement.constCast<RegularQuery>();
std::vector<NormalizedSingleQuery> normalizedSingleQueries;
for (auto i = 0u; i < regularQuery.getNumSingleQueries(); i++) {
scope.clear();
normalizedSingleQueries.push_back(bindSingleQuery(*regularQuery.getSingleQuery(i)));
}
validateUnionColumnsOfTheSameType(normalizedSingleQueries);
DASSERT(!normalizedSingleQueries.empty());
auto boundRegularQuery = std::make_unique<BoundRegularQuery>(regularQuery.getIsUnionAll(),
normalizedSingleQueries[0].getStatementResult()->copy());
for (auto& normalizedSingleQuery : normalizedSingleQueries) {
boundRegularQuery->addSingleQuery(std::move(normalizedSingleQuery));
}
validateIsAllUnionOrUnionAll(*boundRegularQuery);
return boundRegularQuery;
}
NormalizedSingleQuery Binder::bindSingleQuery(const SingleQuery& singleQuery) {
auto normalizedSingleQuery = NormalizedSingleQuery();
for (auto i = 0u; i < singleQuery.getNumQueryParts(); ++i) {
normalizedSingleQuery.appendQueryPart(bindQueryPart(*singleQuery.getQueryPart(i)));
}
auto lastQueryPart = NormalizedQueryPart();
for (auto i = 0u; i < singleQuery.getNumReadingClauses(); i++) {
lastQueryPart.addReadingClause(bindReadingClause(*singleQuery.getReadingClause(i)));
}
for (auto i = 0u; i < singleQuery.getNumUpdatingClauses(); ++i) {
lastQueryPart.addUpdatingClause(bindUpdatingClause(*singleQuery.getUpdatingClause(i)));
}
auto statementResult = BoundStatementResult();
if (singleQuery.hasReturnClause()) {
auto boundReturnClause = bindReturnClause(*singleQuery.getReturnClause());
lastQueryPart.setProjectionBody(boundReturnClause.getProjectionBody()->copy());
statementResult = boundReturnClause.getStatementResult()->copy();
} else {
statementResult = BoundStatementResult::createEmptyResult();
}
normalizedSingleQuery.appendQueryPart(std::move(lastQueryPart));
normalizedSingleQuery.setStatementResult(std::move(statementResult));
return normalizedSingleQuery;
}
NormalizedQueryPart Binder::bindQueryPart(const QueryPart& queryPart) {
auto normalizedQueryPart = NormalizedQueryPart();
for (auto i = 0u; i < queryPart.getNumReadingClauses(); i++) {
normalizedQueryPart.addReadingClause(bindReadingClause(*queryPart.getReadingClause(i)));
}
for (auto i = 0u; i < queryPart.getNumUpdatingClauses(); ++i) {
normalizedQueryPart.addUpdatingClause(bindUpdatingClause(*queryPart.getUpdatingClause(i)));
}
auto boundWithClause = bindWithClause(*queryPart.getWithClause());
normalizedQueryPart.setProjectionBody(boundWithClause.getProjectionBody()->copy());
if (boundWithClause.hasWhereExpression()) {
normalizedQueryPart.setProjectionBodyPredicate(boundWithClause.getWhereExpression());
}
return normalizedQueryPart;
}
} }