progress on query compiler
This commit is contained in:
@@ -40,7 +40,7 @@ std::string criteria_evaluator::evaluate(const abstract_criteria &node) {
|
||||
void criteria_evaluator::visit(const between_criteria &node) {
|
||||
query_.bind_vars.emplace_back(node.col().name());
|
||||
query_.bind_vars.emplace_back(node.col().name());
|
||||
clause_ += prepare_identifier(dialect_, node.col()) + " " + dialect_.token_at(sql::dialect_token::Between) + " ";
|
||||
clause_ += prepare_identifier(dialect_, node.col()) + " " + dialect_.between() + " ";
|
||||
evaluate_value(node.minimum());
|
||||
clause_ += " " + dialect_.token_at(sql::dialect_token::And) + " ";
|
||||
evaluate_value(node.maximum());
|
||||
@@ -94,12 +94,12 @@ void criteria_evaluator::visit(const collection_criteria &node) {
|
||||
|
||||
void criteria_evaluator::visit(const collection_query_criteria &node) {
|
||||
clause_ += prepare_identifier(dialect_, node.col()) +
|
||||
(node.operand() == collection_operator::Out ? " " + dialect_.token_at(sql::dialect_token::Not) + " " : " ") +
|
||||
dialect_.token_at(sql::dialect_token::In) + " (" + node.query().str( dialect_ ) + ")";
|
||||
(node.operand() == collection_operator::Out ? " " + dialect_.not_() + " " : " ") +
|
||||
dialect_.in() + " (" + node.query().str( dialect_ ) + ")";
|
||||
}
|
||||
|
||||
void criteria_evaluator::visit(const like_criteria &node) {
|
||||
clause_ += prepare_criteria(dialect_, node.col()) + " " + dialect_.token_at(sql::dialect_token::Like) +
|
||||
clause_ += prepare_criteria(dialect_, node.col()) + " " + dialect_.like() +
|
||||
" " + dialect_.token_at(sql::dialect_token::BeginStringData) + node.pattern() + dialect_.token_at(
|
||||
sql::dialect_token::EndStringData);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "matador/query/internal/string_builder_utils.hpp"
|
||||
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
void prepare_identifier_string_append(std::string& out, const std::string_view col, const sql::dialect &d) {
|
||||
bool first_part = true;
|
||||
|
||||
const char sq = d.start_quote()[0];
|
||||
const char eq = d.end_quote()[0];
|
||||
|
||||
std::size_t i = 0;
|
||||
while (true) {
|
||||
const std::size_t start = i;
|
||||
|
||||
// find end of part
|
||||
while (i < col.size() && col[i] != '.') {
|
||||
++i;
|
||||
}
|
||||
const std::size_t end = i; // [start, end) is the part
|
||||
|
||||
if (!first_part) {
|
||||
out.push_back('.');
|
||||
}
|
||||
first_part = false;
|
||||
|
||||
// quote_identifier(part) + escape_quotes_in_identifier(part), but streaming:
|
||||
out.push_back(sq);
|
||||
for (std::size_t j = start; j < end; ++j) {
|
||||
const char c = col[j];
|
||||
if (c == eq) out.push_back(eq); // escape " as ""
|
||||
out.push_back(c);
|
||||
}
|
||||
out.push_back(eq);
|
||||
|
||||
if (i >= col.size()) break; // done
|
||||
++i; // skip '.'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,10 @@ table_column sum(const std::string& column) {
|
||||
table_column avg(const std::string& column) {
|
||||
return {sql::sql_function_t::Avg, column};
|
||||
}
|
||||
table_column max(const std::string& column) {
|
||||
table_column maximum(const std::string& column) {
|
||||
return {sql::sql_function_t::Max, column};
|
||||
}
|
||||
table_column min(const std::string& column) {
|
||||
table_column minimum(const std::string& column) {
|
||||
return {sql::sql_function_t::Min, column};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
#include "matador/query/table_column.hpp"
|
||||
|
||||
#include "matador/query/internal/basic_type_to_string_visitor.hpp"
|
||||
#include "matador/query/internal/string_builder_utils.hpp"
|
||||
#include "matador/query/internal/query_parts.hpp"
|
||||
|
||||
#include "matador/sql/query_context.hpp"
|
||||
#include "matador/sql/connection.hpp"
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
#include "matador/utils/string.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
|
||||
sql::query_context query_compiler::compile(const query_data &data,
|
||||
@@ -39,10 +38,10 @@ sql::query_context query_compiler::compile(const query_data &data,
|
||||
|
||||
std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const query_data &data, const table_column &col) {
|
||||
if (col.is_function()) {
|
||||
ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.canonical_name());
|
||||
ctx.prototype.emplace_back(col.name());
|
||||
ctx.prototype.back().change_type(utils::basic_type::Int32);
|
||||
} else {
|
||||
ctx.prototype.emplace_back(col.canonical_name());
|
||||
ctx.prototype.emplace_back(col.name());
|
||||
}
|
||||
|
||||
|
||||
@@ -62,61 +61,30 @@ void query_compiler::visit(internal::query_alter_part& part) {
|
||||
void query_compiler::visit(internal::query_alter_table_part& part) {
|
||||
query_.command = sql::sql_command::SQL_ALTER_TABLE;
|
||||
query_.sql += " " + dialect_->token_at(part.token()) + " " +
|
||||
dialect_->prepare_identifier_string(part.table().name());
|
||||
dialect_->prepare_identifier_string(part.table().name());
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_add_key_constraint_part& part) {
|
||||
query_.sql += " " + dialect_->add_constraint() + " " + part.name();
|
||||
}
|
||||
|
||||
void build_columns(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d);
|
||||
|
||||
void query_compiler::visit(internal::query_add_foreign_key_constraint_part& part) {
|
||||
query_.sql += " " + dialect_->token_at(part.token()) + " (";
|
||||
|
||||
if (part.columns().size() < 2) {
|
||||
for (const auto &col: part.columns()) {
|
||||
query_.sql += dialect_->prepare_identifier_string(col.name());
|
||||
}
|
||||
} else {
|
||||
auto it = part.columns().begin();
|
||||
query_.sql += dialect_->prepare_identifier_string(it->name());
|
||||
for (; it != part.columns().end(); ++it) {
|
||||
query_.sql += ", " + dialect_->prepare_identifier_string(it->name());
|
||||
}
|
||||
}
|
||||
build_columns(query_.sql, part.columns(), *dialect_);
|
||||
query_.sql += ")";
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_add_primary_key_constraint_part& part) {
|
||||
query_.sql += " " + dialect_->primary_key() + " (";
|
||||
|
||||
if (part.columns().size() < 2) {
|
||||
for (const auto &col: part.columns()) {
|
||||
query_.sql += dialect_->prepare_identifier_string(col.name());
|
||||
}
|
||||
} else {
|
||||
auto it = part.columns().begin();
|
||||
query_.sql += dialect_->prepare_identifier_string(it->name());
|
||||
for (; it != part.columns().end(); ++it) {
|
||||
query_.sql += ", " + dialect_->prepare_identifier_string(it->name());
|
||||
}
|
||||
}
|
||||
query_.sql += ")";
|
||||
query_.sql += " " + dialect_->primary_key() + " (";
|
||||
build_columns(query_.sql, part.columns(), *dialect_);
|
||||
query_.sql += ")";
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_add_foreign_key_reference_part& part) {
|
||||
query_.sql += " " + dialect_->token_at(part.token()) + " " + part.table().name() + " (";
|
||||
|
||||
if (part.columns().size() < 2) {
|
||||
for (const auto &col: part.columns()) {
|
||||
query_.sql += dialect_->prepare_identifier_string(col.name());
|
||||
}
|
||||
} else {
|
||||
auto it = part.columns().begin();
|
||||
query_.sql += dialect_->prepare_identifier_string(it->name());
|
||||
for (; it != part.columns().end(); ++it) {
|
||||
query_.sql += ", " + dialect_->prepare_identifier_string(it->name());
|
||||
}
|
||||
}
|
||||
build_columns(query_.sql, part.columns(), *dialect_);
|
||||
query_.sql += ")";
|
||||
}
|
||||
|
||||
@@ -198,7 +166,7 @@ void query_compiler::visit(internal::query_group_by_part &part) {
|
||||
query_.sql += " " + dialect_->group_by() + " ";
|
||||
if (part.columns().size() < 2) {
|
||||
for (const auto &col: part.columns()) {
|
||||
query_.sql.append(dialect_->prepare_identifier_string(col.canonical_name()));
|
||||
query_.sql.append(dialect_->prepare_identifier_string(col.name()));
|
||||
}
|
||||
} else {
|
||||
auto it = part.columns().begin();
|
||||
@@ -250,23 +218,10 @@ void query_compiler::visit(internal::query_insert_part &/*insert_part*/) {
|
||||
void query_compiler::visit(internal::query_into_part &part) {
|
||||
query_.table_name = part.table().name();
|
||||
query_.sql += " " + dialect_->into() +
|
||||
" " + dialect_->prepare_identifier_string(part.table().name());
|
||||
" " + dialect_->prepare_identifier_string(part.table().name()) + " (";
|
||||
|
||||
std::string result{"("};
|
||||
if (part.columns().size() < 2) {
|
||||
for (const auto &col: part.columns()) {
|
||||
result.append(dialect_->prepare_identifier_string(col.name()));
|
||||
}
|
||||
} else {
|
||||
auto it = part.columns().begin();
|
||||
result.append(dialect_->prepare_identifier_string((it++)->name()));
|
||||
for (; it != part.columns().end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(dialect_->prepare_identifier_string(it->name()));
|
||||
}
|
||||
}
|
||||
result += (")");
|
||||
query_.sql += " " + result;
|
||||
build_columns(query_.sql, part.columns(), *dialect_);
|
||||
query_.sql += ")"/* + result*/;
|
||||
}
|
||||
|
||||
struct value_visitor {
|
||||
@@ -341,7 +296,7 @@ void query_compiler::visit(internal::query_create_part &/*create_part*/)
|
||||
query_.sql = dialect_->create();
|
||||
}
|
||||
|
||||
std::string build_create_column(const table_column &col, const sql::dialect &d);
|
||||
void build_create_column(std::string &out, const table_column &col, const sql::dialect &d);
|
||||
std::string build_constraint(const table_constraint &cons, const sql::dialect &d);
|
||||
|
||||
void query_compiler::visit(internal::query_create_table_part &part)
|
||||
@@ -353,22 +308,14 @@ void query_compiler::visit(internal::query_create_table_part &part)
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_create_table_columns_part& part) {
|
||||
std::string result;
|
||||
|
||||
if (part.columns().size() < 2) {
|
||||
for (const auto &col: part.columns()) {
|
||||
result.append(build_create_column(col, *dialect_));
|
||||
}
|
||||
} else {
|
||||
auto it = part.columns().begin();
|
||||
result.append(build_create_column(*it++, *dialect_));
|
||||
for (; it != part.columns().end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(build_create_column(*it, *dialect_));
|
||||
bool first = true;
|
||||
for (const auto& col : part.columns()) {
|
||||
if (!first) {
|
||||
query_.sql.append(", ");
|
||||
}
|
||||
build_create_column(query_.sql, col, *dialect_);
|
||||
first = false;
|
||||
}
|
||||
|
||||
query_.sql += result;
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_create_table_constraints_part& part) {
|
||||
@@ -425,22 +372,31 @@ void query_compiler::visit(internal::query_drop_table_part &part) {
|
||||
query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name);
|
||||
}
|
||||
|
||||
std::string build_create_column(const table_column &col, const sql::dialect &d) {
|
||||
std::string result = d.prepare_identifier_string(col.name()) + " " + d.data_type_at(col.type());
|
||||
void build_create_column(std::string &out, const table_column &col, const sql::dialect &d) {
|
||||
prepare_identifier_string_append(out, col.canonical_name(), d);
|
||||
out += " " + d.data_type_at(col.type());
|
||||
if (col.attributes().size() > 0) {
|
||||
result.append("(" + std::to_string(col.attributes().size()) + ")");
|
||||
out.append("(" + std::to_string(col.attributes().size()) + ")");
|
||||
}
|
||||
if (!col.is_nullable()) {
|
||||
result.append(" ").append(d.not_null());
|
||||
out.append(" ").append(d.not_null());
|
||||
}
|
||||
if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) {
|
||||
result.append(" ").append(d.unique());
|
||||
out.append(" ").append(d.unique());
|
||||
}
|
||||
if (is_constraint_set(col.attributes().options(), utils::constraints::PrimaryKey)) {
|
||||
result.append(" ").append(d.primary_key());
|
||||
out.append(" ").append(d.primary_key());
|
||||
}
|
||||
}
|
||||
void build_columns(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d) {
|
||||
bool first = true;
|
||||
for (const auto& col : cols) {
|
||||
if (!first) {
|
||||
out.append(", ");
|
||||
}
|
||||
prepare_identifier_string_append(out, col.name(), d);
|
||||
first = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string build_constraint(const table_constraint& cons, const sql::dialect& d) {
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
#include "matador/query/query_utils.hpp"
|
||||
|
||||
#include "matador/query/table.hpp"
|
||||
#include "matador/query/internal/string_builder_utils.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
std::string prepare_identifier(const sql::dialect& d, const table_column& col) {
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
if (col.table()) {
|
||||
result = d.prepare_identifier_string(col.table()->name()) + ".";
|
||||
}
|
||||
result += d.prepare_identifier_string(col.name());
|
||||
prepare_identifier_string_append(result, col.name(), d);
|
||||
} else {
|
||||
result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
|
||||
}
|
||||
if (!col.alias().empty()) {
|
||||
result += " AS " + col.alias();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string prepare_criteria(const sql::dialect& d, const table_column& col) {
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
if (col.table()) {
|
||||
result = d.prepare_identifier_string(col.table()->name()) + ".";
|
||||
}
|
||||
result += d.prepare_identifier_string(col.name());
|
||||
prepare_identifier_string_append(result, col.name(), d);
|
||||
} else {
|
||||
result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ table::table(const std::string& name, const std::vector<table_column> &columns)
|
||||
: table(name, name, columns) {
|
||||
}
|
||||
|
||||
table::table(std::string name, std::string alias, const std::vector<table_column> &columns)
|
||||
table::table(std::string name, std::string alias, const std::vector<table_column> &columns)
|
||||
: name_(std::move(name))
|
||||
, alias_(std::move(alias))
|
||||
, columns_(columns) {
|
||||
@@ -91,7 +91,7 @@ const table_column* table::operator[](const std::string &column_name) const {
|
||||
|
||||
const table_column * table::column_by_name(const table &tab, const std::string &column_name) {
|
||||
for (const auto &col : tab.columns_) {
|
||||
if (col.name() == column_name) {
|
||||
if (col.column_name() == column_name) {
|
||||
return &col;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,42 +25,39 @@ table_column::table_column(const char *name)
|
||||
: table_column(std::string(name))
|
||||
{}
|
||||
|
||||
table_column::table_column(std::string name)
|
||||
: name_(std::move(name)) {}
|
||||
table_column::table_column(std::string name, std::string alias)
|
||||
: name_(std::move(name))
|
||||
, alias_(std::move(alias)) {}
|
||||
table_column::table_column(const std::string& name)
|
||||
: table_column(name, name) {}
|
||||
|
||||
table_column::table_column(const sql::sql_function_t func, std::string name)
|
||||
: name_(std::move(name))
|
||||
, function_(func) {}
|
||||
table_column::table_column(const std::string& name, const std::string& alias)
|
||||
: table_column(nullptr, name, alias, utils::basic_type::Unknown, {}, sql::sql_function_t::None)
|
||||
{}
|
||||
|
||||
table_column::table_column(const class table* tab, std::string name)
|
||||
: table_(tab)
|
||||
, name_(std::move(name)) {}
|
||||
table_column::table_column(const sql::sql_function_t func, const std::string& name)
|
||||
: table_column(nullptr, name, name, utils::basic_type::Unknown, {}, func)
|
||||
{}
|
||||
|
||||
table_column::table_column(const class table* tab, std::string name, std::string alias)
|
||||
: table_(tab)
|
||||
, name_(std::move(name))
|
||||
, alias_(std::move(alias)) {}
|
||||
table_column::table_column(const class table* tab,
|
||||
std::string name,
|
||||
const utils::basic_type type,
|
||||
const utils::field_attributes& attributes)
|
||||
: table_(tab)
|
||||
, name_(std::move(name))
|
||||
, type_(type)
|
||||
, attributes_(attributes) {}
|
||||
table_column::table_column(const class table* tab, const std::string& name)
|
||||
: table_column(tab, name, name, utils::basic_type::Unknown, {}, sql::sql_function_t::None)
|
||||
{}
|
||||
|
||||
table_column::table_column(const class table* tab, const std::string& name, const std::string& alias)
|
||||
: table_column(tab, name, alias, utils::basic_type::Unknown, {}, sql::sql_function_t::None)
|
||||
{}
|
||||
|
||||
table_column::table_column(const class table* tab, const std::string& name, const utils::basic_type type, const utils::field_attributes& attributes)
|
||||
: table_column(tab, name, name, type, attributes, sql::sql_function_t::None)
|
||||
{}
|
||||
|
||||
table_column::table_column(const class table* tab,
|
||||
std::string name,
|
||||
std::string alias,
|
||||
utils::basic_type type,
|
||||
const utils::field_attributes &attributes,
|
||||
const sql::sql_function_t func)
|
||||
const std::string& name,
|
||||
const std::string& alias,
|
||||
const utils::basic_type type,
|
||||
const utils::field_attributes &attributes,
|
||||
const sql::sql_function_t func)
|
||||
: table_(tab)
|
||||
, name_(std::move(name))
|
||||
, alias_(std::move(alias))
|
||||
, name_(build_column_name(table_, name))
|
||||
, column_name_(name)
|
||||
, alias_(alias)
|
||||
, type_(type)
|
||||
, attributes_(attributes)
|
||||
, function_(func) {}
|
||||
@@ -71,6 +68,7 @@ table_column & table_column::operator=(const table_column &other) {
|
||||
}
|
||||
table_ = other.table_;
|
||||
name_ = other.name_;
|
||||
column_name_ = other.column_name_;
|
||||
alias_ = other.alias_;
|
||||
type_ = other.type_;
|
||||
attributes_ = other.attributes_;
|
||||
@@ -82,6 +80,7 @@ bool table_column::equals(const table_column &x) const {
|
||||
if (table_ != nullptr && x.table_ != nullptr) {
|
||||
return *table_ == *x.table_ &&
|
||||
name_ == x.name_ &&
|
||||
column_name_ == x.column_name_ &&
|
||||
alias_ == x.alias_ &&
|
||||
function_ == x.function_;
|
||||
}
|
||||
@@ -92,15 +91,19 @@ bool table_column::equals(const table_column &x) const {
|
||||
}
|
||||
|
||||
table_column table_column::as(const std::string& alias) const {
|
||||
return {table_, name_, alias, type_, attributes_, function_};
|
||||
return {table_, column_name_, alias, type_, attributes_, function_};
|
||||
}
|
||||
|
||||
const std::string& table_column::name() const {
|
||||
return name_;
|
||||
return has_alias() ? alias_ : name_;
|
||||
}
|
||||
|
||||
std::string table_column::canonical_name() const {
|
||||
return table_ ? table_->name() + "." + name_ : name_;
|
||||
const std::string& table_column::column_name() const {
|
||||
return column_name_;
|
||||
}
|
||||
|
||||
const std::string& table_column::canonical_name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string& table_column::alias() const {
|
||||
@@ -128,7 +131,7 @@ sql::sql_function_t table_column::function() const {
|
||||
}
|
||||
|
||||
bool table_column::has_alias() const {
|
||||
return !alias_.empty();
|
||||
return alias_ != column_name_;
|
||||
}
|
||||
|
||||
const class table* table_column::table() const {
|
||||
@@ -137,9 +140,14 @@ const class table* table_column::table() const {
|
||||
|
||||
void table_column::table(const query::table* tab) {
|
||||
table_ = tab;
|
||||
name_ = build_column_name(table_, column_name_);
|
||||
}
|
||||
|
||||
table_column::operator const std::string&() const {
|
||||
return name_;
|
||||
return name();
|
||||
}
|
||||
|
||||
std::string table_column::build_column_name(const class query::table* tab, const std::string& name) {
|
||||
return tab ? tab->name() + "." + name : name;
|
||||
}
|
||||
} // namespace matador::query
|
||||
|
||||
Reference in New Issue
Block a user