progress on query compiler

This commit is contained in:
Sascha Kühl
2026-01-22 16:14:42 +01:00
parent b331ef6923
commit 686b1ddb7a
19 changed files with 241 additions and 175 deletions
+4 -4
View File
@@ -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 '.'
}
}
}
+2 -2
View File
@@ -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};
}
+39 -83
View File
@@ -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) {
+3 -11
View File
@@ -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() + ")";
}
+2 -2
View File
@@ -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;
}
}
+44 -36
View File
@@ -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