1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:27:46 +00:00

LibSQL+SQLServer: Return the new Result class from statement executions

We can now TRY anything that returns a SQL::Result or an AK::Error.
This commit is contained in:
Timothy Flynn 2022-02-09 15:57:57 -05:00 committed by Linus Groh
parent d9055de7ea
commit 6620f19979
11 changed files with 337 additions and 337 deletions

View file

@ -298,7 +298,7 @@ private:
struct ExecutionContext {
NonnullRefPtr<Database> database;
RefPtr<SQLResult> result { nullptr };
Optional<Result> result;
class Statement const* statement;
Tuple* current_row { nullptr };
};
@ -725,8 +725,12 @@ private:
class Statement : public ASTNode {
public:
RefPtr<SQLResult> execute(AK::NonnullRefPtr<Database> database) const;
virtual RefPtr<SQLResult> execute(ExecutionContext&) const { return nullptr; }
Result execute(AK::NonnullRefPtr<Database> database) const;
virtual Result execute(ExecutionContext&) const
{
return { SQLCommand::Unknown, SQLErrorCode::NotYetImplemented };
}
};
class ErrorStatement final : public Statement {
@ -743,7 +747,7 @@ public:
const String& schema_name() const { return m_schema_name; }
bool is_error_if_schema_exists() const { return m_is_error_if_schema_exists; }
RefPtr<SQLResult> execute(ExecutionContext&) const override;
Result execute(ExecutionContext&) const override;
private:
String m_schema_name;
@ -782,7 +786,7 @@ public:
bool is_temporary() const { return m_is_temporary; }
bool is_error_if_table_exists() const { return m_is_error_if_table_exists; }
RefPtr<SQLResult> execute(ExecutionContext&) const override;
Result execute(ExecutionContext&) const override;
private:
String m_schema_name;
@ -945,7 +949,7 @@ public:
bool has_selection() const { return !m_select_statement.is_null(); }
const RefPtr<Select>& select_statement() const { return m_select_statement; }
virtual RefPtr<SQLResult> execute(ExecutionContext&) const override;
virtual Result execute(ExecutionContext&) const override;
private:
RefPtr<CommonTableExpressionList> m_common_table_expression_list;
@ -1038,7 +1042,7 @@ public:
const RefPtr<GroupByClause>& group_by_clause() const { return m_group_by_clause; }
const NonnullRefPtrVector<OrderingTerm>& ordering_term_list() const { return m_ordering_term_list; }
const RefPtr<LimitClause>& limit_clause() const { return m_limit_clause; }
RefPtr<SQLResult> execute(ExecutionContext&) const override;
Result execute(ExecutionContext&) const override;
private:
RefPtr<CommonTableExpressionList> m_common_table_expression_list;
@ -1059,7 +1063,7 @@ public:
}
NonnullRefPtr<QualifiedTableName> qualified_table_name() const { return m_qualified_table_name; }
RefPtr<SQLResult> execute(ExecutionContext&) const override;
Result execute(ExecutionContext&) const override;
private:
NonnullRefPtr<QualifiedTableName> m_qualified_table_name;

View file

@ -10,23 +10,20 @@
namespace SQL::AST {
RefPtr<SQLResult> CreateSchema::execute(ExecutionContext& context) const
Result CreateSchema::execute(ExecutionContext& context) const
{
auto schema_def_or_error = context.database->get_schema(m_schema_name);
if (schema_def_or_error.is_error())
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::InternalError, schema_def_or_error.error());
auto schema_def = schema_def_or_error.release_value();
auto schema_def = TRY(context.database->get_schema(m_schema_name));
if (schema_def) {
if (m_is_error_if_schema_exists) {
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::SchemaExists, m_schema_name);
}
return SQLResult::construct(SQLCommand::Create);
if (m_is_error_if_schema_exists)
return { SQLCommand::Create, SQLErrorCode::SchemaExists, m_schema_name };
return { SQLCommand::Create };
}
schema_def = SchemaDef::construct(m_schema_name);
if (auto maybe_error = context.database->add_schema(*schema_def); maybe_error.is_error())
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::InternalError, maybe_error.error());
return SQLResult::construct(SQLCommand::Create, 0, 1);
TRY(context.database->add_schema(*schema_def));
return { SQLCommand::Create, 0, 1 };
}
}

View file

@ -9,43 +9,40 @@
namespace SQL::AST {
RefPtr<SQLResult> CreateTable::execute(ExecutionContext& context) const
Result CreateTable::execute(ExecutionContext& context) const
{
auto schema_name = (!m_schema_name.is_null() && !m_schema_name.is_empty()) ? m_schema_name : "default";
auto schema_def_or_error = context.database->get_schema(schema_name);
if (schema_def_or_error.is_error())
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::InternalError, schema_def_or_error.error());
auto schema_def = schema_def_or_error.release_value();
auto schema_name = m_schema_name.is_empty() ? String { "default"sv } : m_schema_name;
auto schema_def = TRY(context.database->get_schema(schema_name));
if (!schema_def)
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::SchemaDoesNotExist, m_schema_name);
auto table_def_or_error = context.database->get_table(schema_name, m_table_name);
if (table_def_or_error.is_error())
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::InternalError, table_def_or_error.error());
auto table_def = table_def_or_error.release_value();
return { SQLCommand::Create, SQLErrorCode::SchemaDoesNotExist, schema_name };
auto table_def = TRY(context.database->get_table(schema_name, m_table_name));
if (table_def) {
if (m_is_error_if_table_exists) {
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::TableExists, m_table_name);
} else {
return SQLResult::construct(SQLCommand::Create);
}
if (m_is_error_if_table_exists)
return { SQLCommand::Create, SQLErrorCode::TableExists, m_table_name };
return { SQLCommand::Create };
}
table_def = TableDef::construct(schema_def, m_table_name);
for (auto& column : m_columns) {
SQLType type;
if (column.type_name()->name() == "VARCHAR" || column.type_name()->name() == "TEXT") {
if (column.type_name()->name().is_one_of("VARCHAR"sv, "TEXT"sv))
type = SQLType::Text;
} else if (column.type_name()->name() == "INT" || column.type_name()->name() == "INTEGER") {
else if (column.type_name()->name().is_one_of("INT"sv, "INTEGER"sv))
type = SQLType::Integer;
} else if (column.type_name()->name() == "FLOAT" || column.type_name()->name() == "NUMBER") {
else if (column.type_name()->name().is_one_of("FLOAT"sv, "NUMBER"sv))
type = SQLType::Float;
} else {
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::InvalidType, column.type_name()->name());
}
else
return { SQLCommand::Create, SQLErrorCode::InvalidType, column.type_name()->name() };
table_def->append_column(column.name(), type);
}
if (auto maybe_error = context.database->add_table(*table_def); maybe_error.is_error())
return SQLResult::construct(SQLCommand::Create, SQLErrorCode::InternalError, maybe_error.release_error());
return SQLResult::construct(SQLCommand::Create, 0, 1);
TRY(context.database->add_table(*table_def));
return { SQLCommand::Create, 0, 1 };
}
}

View file

@ -11,32 +11,31 @@
namespace SQL::AST {
RefPtr<SQLResult> DescribeTable::execute(ExecutionContext& context) const
Result DescribeTable::execute(ExecutionContext& context) const
{
auto schema_name = m_qualified_table_name->schema_name();
auto table_name = m_qualified_table_name->table_name();
auto table_def_or_error = context.database->get_table(schema_name, table_name);
auto table_def = table_def_or_error.release_value();
auto table_def = TRY(context.database->get_table(schema_name, table_name));
if (!table_def) {
if (schema_name.is_null() || schema_name.is_empty())
schema_name = "default";
return SQLResult::construct(SQLCommand::Describe, SQLErrorCode::TableDoesNotExist, String::formatted("{}.{}", schema_name, table_name));
if (schema_name.is_empty())
schema_name = "default"sv;
return { SQLCommand::Describe, SQLErrorCode::TableDoesNotExist, String::formatted("{}.{}", schema_name, table_name) };
}
auto describe_table_def = context.database->get_table("master", "internal_describe_table").value();
NonnullRefPtr<TupleDescriptor> descriptor = describe_table_def->to_tuple_descriptor();
auto describe_table_def = MUST(context.database->get_table("master"sv, "internal_describe_table"sv));
auto descriptor = describe_table_def->to_tuple_descriptor();
context.result = SQLResult::construct();
Result result { SQLCommand::Describe };
for (auto& column : table_def->columns()) {
Tuple tuple(descriptor);
tuple[0] = column.name();
tuple[1] = SQLType_name(column.type());
context.result->insert(tuple, Tuple {});
result.insert(tuple, Tuple {});
}
return context.result;
return result;
}
}

View file

@ -19,7 +19,7 @@ Value Expression::evaluate(ExecutionContext&) const
Value NumericLiteral::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
Value ret(SQLType::Float);
ret = value();
@ -28,7 +28,7 @@ Value NumericLiteral::evaluate(ExecutionContext& context) const
Value StringLiteral::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
Value ret(SQLType::Text);
ret = value();
@ -42,14 +42,14 @@ Value NullLiteral::evaluate(ExecutionContext&) const
Value NestedExpression::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
return expression()->evaluate(context);
}
Value ChainedExpression::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
Value ret(SQLType::Tuple);
Vector<Value> values;
@ -62,14 +62,14 @@ Value ChainedExpression::evaluate(ExecutionContext& context) const
Value BinaryOperatorExpression::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
Value lhs_value = lhs()->evaluate(context);
Value rhs_value = rhs()->evaluate(context);
switch (type()) {
case BinaryOperator::Concatenate: {
if (lhs_value.type() != SQLType::Text) {
context.result->set_error(SQLErrorCode::BooleanOperatorTypeMismatch, BinaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::BooleanOperatorTypeMismatch, BinaryOperator_name(type()) };
return Value::null();
}
AK::StringBuilder builder;
@ -111,7 +111,7 @@ Value BinaryOperatorExpression::evaluate(ExecutionContext& context) const
auto lhs_bool_maybe = lhs_value.to_bool();
auto rhs_bool_maybe = rhs_value.to_bool();
if (!lhs_bool_maybe.has_value() || !rhs_bool_maybe.has_value()) {
context.result->set_error(SQLErrorCode::BooleanOperatorTypeMismatch, BinaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::BooleanOperatorTypeMismatch, BinaryOperator_name(type()) };
return Value::null();
}
return Value(lhs_bool_maybe.release_value() && rhs_bool_maybe.release_value());
@ -120,7 +120,7 @@ Value BinaryOperatorExpression::evaluate(ExecutionContext& context) const
auto lhs_bool_maybe = lhs_value.to_bool();
auto rhs_bool_maybe = rhs_value.to_bool();
if (!lhs_bool_maybe.has_value() || !rhs_bool_maybe.has_value()) {
context.result->set_error(SQLErrorCode::BooleanOperatorTypeMismatch, BinaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::BooleanOperatorTypeMismatch, BinaryOperator_name(type()) };
return Value::null();
}
return Value(lhs_bool_maybe.release_value() || rhs_bool_maybe.release_value());
@ -132,14 +132,14 @@ Value BinaryOperatorExpression::evaluate(ExecutionContext& context) const
Value UnaryOperatorExpression::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
Value expression_value = NestedExpression::evaluate(context);
switch (type()) {
case UnaryOperator::Plus:
if (expression_value.type() == SQLType::Integer || expression_value.type() == SQLType::Float)
return expression_value;
context.result->set_error(SQLErrorCode::NumericOperatorTypeMismatch, UnaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::NumericOperatorTypeMismatch, UnaryOperator_name(type()) };
return Value::null();
case UnaryOperator::Minus:
if (expression_value.type() == SQLType::Integer) {
@ -150,21 +150,21 @@ Value UnaryOperatorExpression::evaluate(ExecutionContext& context) const
expression_value = -double(expression_value);
return expression_value;
}
context.result->set_error(SQLErrorCode::NumericOperatorTypeMismatch, UnaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::NumericOperatorTypeMismatch, UnaryOperator_name(type()) };
return Value::null();
case UnaryOperator::Not:
if (expression_value.type() == SQLType::Boolean) {
expression_value = !bool(expression_value);
return expression_value;
}
context.result->set_error(SQLErrorCode::BooleanOperatorTypeMismatch, UnaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::BooleanOperatorTypeMismatch, UnaryOperator_name(type()) };
return Value::null();
case UnaryOperator::BitwiseNot:
if (expression_value.type() == SQLType::Integer) {
expression_value = ~u32(expression_value);
return expression_value;
}
context.result->set_error(SQLErrorCode::IntegerOperatorTypeMismatch, UnaryOperator_name(type()));
context.result = Result { SQLCommand::Unknown, SQLErrorCode::IntegerOperatorTypeMismatch, UnaryOperator_name(type()) };
return Value::null();
}
VERIFY_NOT_REACHED();
@ -173,7 +173,7 @@ Value UnaryOperatorExpression::evaluate(ExecutionContext& context) const
Value ColumnNameExpression::evaluate(ExecutionContext& context) const
{
if (!context.current_row) {
context.result->set_error(SQLErrorCode::SyntaxError, column_name());
context.result = Result { SQLCommand::Unknown, SQLErrorCode::SyntaxError, column_name() };
return Value::null();
}
auto& descriptor = *context.current_row->descriptor();
@ -185,7 +185,7 @@ Value ColumnNameExpression::evaluate(ExecutionContext& context) const
continue;
if (column_descriptor.name == column_name()) {
if (index_in_row.has_value()) {
context.result->set_error(SQLErrorCode::AmbiguousColumnName, column_name());
context.result = Result { SQLCommand::Unknown, SQLErrorCode::AmbiguousColumnName, column_name() };
return Value::null();
}
index_in_row = ix;
@ -193,13 +193,13 @@ Value ColumnNameExpression::evaluate(ExecutionContext& context) const
}
if (index_in_row.has_value())
return (*context.current_row)[index_in_row.value()];
context.result->set_error(SQLErrorCode::ColumnDoesNotExist, column_name());
context.result = Result { SQLCommand::Unknown, SQLErrorCode::ColumnDoesNotExist, column_name() };
return Value::null();
}
Value MatchExpression::evaluate(ExecutionContext& context) const
{
if (context.result->has_error())
if (context.result->is_error())
return Value::null();
switch (type()) {
case MatchOperator::Like: {
@ -209,7 +209,7 @@ Value MatchExpression::evaluate(ExecutionContext& context) const
if (escape()) {
auto escape_str = escape()->evaluate(context).to_string();
if (escape_str.length() != 1) {
context.result->set_error(SQLErrorCode::SyntaxError, "ESCAPE should be a single character");
context.result = Result { SQLCommand::Unknown, SQLErrorCode::SyntaxError, "ESCAPE should be a single character" };
return Value::null();
}
escape_char = escape_str[0];
@ -253,7 +253,7 @@ Value MatchExpression::evaluate(ExecutionContext& context) const
builder.append("Regular expression: ");
builder.append(get_error_string(err));
context.result->set_error(SQLErrorCode::SyntaxError, builder.build());
context.result = Result { SQLCommand::Unknown, SQLErrorCode::SyntaxError, builder.build() };
return Value(false);
}

View file

@ -14,78 +14,69 @@ namespace SQL::AST {
static bool does_value_data_type_match(SQLType expected, SQLType actual)
{
if (actual == SQLType::Null) {
if (actual == SQLType::Null)
return false;
}
if (expected == SQLType::Integer) {
if (expected == SQLType::Integer)
return actual == SQLType::Integer || actual == SQLType::Float;
}
return expected == actual;
}
RefPtr<SQLResult> Insert::execute(ExecutionContext& context) const
Result Insert::execute(ExecutionContext& context) const
{
auto table_def_or_error = context.database->get_table(m_schema_name, m_table_name);
if (table_def_or_error.is_error())
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::InternalError, table_def_or_error.release_error());
auto table_def = table_def_or_error.release_value();
auto table_def = TRY(context.database->get_table(m_schema_name, m_table_name));
if (!table_def) {
auto schema_name = m_schema_name;
if (schema_name.is_null() || schema_name.is_empty())
schema_name = "default";
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::TableDoesNotExist, String::formatted("{}.{}", schema_name, m_table_name));
auto schema_name = m_schema_name.is_empty() ? String("default"sv) : m_schema_name;
return { SQLCommand::Insert, SQLErrorCode::TableDoesNotExist, String::formatted("{}.{}", schema_name, m_table_name) };
}
Row row(table_def);
for (auto& column : m_column_names) {
if (!row.has(column)) {
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::ColumnDoesNotExist, column);
}
if (!row.has(column))
return { SQLCommand::Insert, SQLErrorCode::ColumnDoesNotExist, column };
}
Vector<Row> inserted_rows;
inserted_rows.ensure_capacity(m_chained_expressions.size());
context.result = SQLResult::construct();
TRY(inserted_rows.try_ensure_capacity(m_chained_expressions.size()));
context.result = Result { SQLCommand::Insert };
for (auto& row_expr : m_chained_expressions) {
for (auto& column_def : table_def->columns()) {
if (!m_column_names.contains_slow(column_def.name())) {
if (!m_column_names.contains_slow(column_def.name()))
row[column_def.name()] = column_def.default_value();
}
}
auto row_value = row_expr.evaluate(context);
if (context.result->has_error())
return context.result;
if (context.result->is_error())
return context.result.release_value();
VERIFY(row_value.type() == SQLType::Tuple);
auto values = row_value.to_vector().value();
if (m_column_names.size() == 0 && values.size() != row.size()) {
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::InvalidNumberOfValues, "");
}
if (m_column_names.is_empty() && values.size() != row.size())
return { SQLCommand::Insert, SQLErrorCode::InvalidNumberOfValues, String::empty() };
for (auto ix = 0u; ix < values.size(); ix++) {
auto input_value_type = values[ix].type();
auto& tuple_descriptor = *row.descriptor();
// In case of having column names, this must succeed since we checked for every column name for existence in the table.
auto element_index = (m_column_names.size() == 0) ? ix : tuple_descriptor.find_if([&](auto element) { return element.name == m_column_names[ix]; }).index();
auto element_index = m_column_names.is_empty() ? ix : tuple_descriptor.find_if([&](auto element) { return element.name == m_column_names[ix]; }).index();
auto element_type = tuple_descriptor[element_index].type;
if (!does_value_data_type_match(element_type, input_value_type)) {
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::InvalidValueType, table_def->columns()[element_index].name());
}
if (!does_value_data_type_match(element_type, input_value_type))
return { SQLCommand::Insert, SQLErrorCode::InvalidValueType, table_def->columns()[element_index].name() };
row[element_index] = values[ix];
}
inserted_rows.append(row);
}
for (auto& inserted_row : inserted_rows) {
if (auto maybe_error = context.database->insert(inserted_row); maybe_error.is_error())
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::InternalError, maybe_error.release_error());
}
for (auto& inserted_row : inserted_rows)
TRY(context.database->insert(inserted_row));
return SQLResult::construct(SQLCommand::Insert, 0, m_chained_expressions.size(), 0);
return { SQLCommand::Insert, 0, m_chained_expressions.size() };
}
}

View file

@ -13,65 +13,67 @@
namespace SQL::AST {
RefPtr<SQLResult> Select::execute(ExecutionContext& context) const
Result Select::execute(ExecutionContext& context) const
{
NonnullRefPtrVector<ResultColumn> columns;
auto const& result_column_list = this->result_column_list();
VERIFY(!result_column_list.is_empty());
for (auto& table_descriptor : table_or_subquery_list()) {
if (!table_descriptor.is_table())
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::NotYetImplemented, "Sub-selects are not yet implemented");
auto table_def_or_error = context.database->get_table(table_descriptor.schema_name(), table_descriptor.table_name());
if (table_def_or_error.is_error())
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::InternalError, table_def_or_error.error());
auto table = table_def_or_error.value();
if (!table) {
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::TableDoesNotExist, table_descriptor.table_name());
}
return { SQLCommand::Select, SQLErrorCode::NotYetImplemented, "Sub-selects are not yet implemented"sv };
if (result_column_list().size() == 1 && result_column_list()[0].type() == ResultType::All) {
for (auto& col : table->columns()) {
auto table_def = TRY(context.database->get_table(table_descriptor.schema_name(), table_descriptor.table_name()));
if (!table_def)
return { SQLCommand::Select, SQLErrorCode::TableDoesNotExist, table_descriptor.table_name() };
if (result_column_list.size() == 1 && result_column_list[0].type() == ResultType::All) {
for (auto& col : table_def->columns()) {
columns.append(
create_ast_node<ResultColumn>(
create_ast_node<ColumnNameExpression>(table->parent()->name(), table->name(), col.name()),
create_ast_node<ColumnNameExpression>(table_def->parent()->name(), table_def->name(), col.name()),
""));
}
}
}
VERIFY(!result_column_list().is_empty());
if (result_column_list().size() != 1 || result_column_list()[0].type() != ResultType::All) {
for (auto& col : result_column_list()) {
if (col.type() == ResultType::All)
if (result_column_list.size() != 1 || result_column_list[0].type() != ResultType::All) {
for (auto& col : result_column_list) {
if (col.type() == ResultType::All) {
// FIXME can have '*' for example in conjunction with computed columns
return SQLResult::construct(SQL::SQLCommand::Select, SQLErrorCode::SyntaxError, "*");
return { SQLCommand::Select, SQLErrorCode::SyntaxError, "*"sv };
}
columns.append(col);
}
}
context.result = SQLResult::construct();
AK::NonnullRefPtr<TupleDescriptor> descriptor = AK::adopt_ref(*new TupleDescriptor);
context.result = Result { SQLCommand::Select };
auto descriptor = adopt_ref(*new TupleDescriptor);
Tuple tuple(descriptor);
Vector<Tuple> rows;
descriptor->empend("__unity__");
descriptor->empend("__unity__"sv);
tuple.append(Value(SQLType::Boolean, true));
rows.append(tuple);
for (auto& table_descriptor : table_or_subquery_list()) {
if (!table_descriptor.is_table())
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::NotYetImplemented, "Sub-selects are not yet implemented");
auto table_def_or_error = context.database->get_table(table_descriptor.schema_name(), table_descriptor.table_name());
if (table_def_or_error.is_error())
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::InternalError, table_def_or_error.error());
auto table = table_def_or_error.value();
if (table->num_columns() == 0)
return { SQLCommand::Select, SQLErrorCode::NotYetImplemented, "Sub-selects are not yet implemented"sv };
auto table_def = TRY(context.database->get_table(table_descriptor.schema_name(), table_descriptor.table_name()));
if (table_def->num_columns() == 0)
continue;
auto old_descriptor_size = descriptor->size();
descriptor->extend(table->to_tuple_descriptor());
descriptor->extend(table_def->to_tuple_descriptor());
for (auto cartesian_row = rows.first(); cartesian_row.size() == old_descriptor_size; cartesian_row = rows.first()) {
rows.remove(0);
auto table_rows_or_error = context.database->select_all(*table);
if (table_rows_or_error.is_error())
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::InternalError, table_rows_or_error.error());
for (auto& table_row : table_rows_or_error.value()) {
auto table_rows = TRY(context.database->select_all(*table_def));
for (auto& table_row : table_rows) {
auto new_row = cartesian_row;
new_row.extend(table_row);
rows.append(new_row);
@ -80,7 +82,7 @@ RefPtr<SQLResult> Select::execute(ExecutionContext& context) const
}
bool has_ordering { false };
AK::NonnullRefPtr<TupleDescriptor> sort_descriptor = AK::adopt_ref(*new TupleDescriptor);
auto sort_descriptor = adopt_ref(*new TupleDescriptor);
for (auto& term : m_ordering_term_list) {
sort_descriptor->append(TupleElementDescriptor { .order = term.order() });
has_ordering = true;
@ -89,18 +91,21 @@ RefPtr<SQLResult> Select::execute(ExecutionContext& context) const
for (auto& row : rows) {
context.current_row = &row;
if (where_clause()) {
auto where_result = where_clause()->evaluate(context);
if (context.result->has_error())
return context.result;
if (context.result->is_error())
return context.result.release_value();
if (!where_result)
continue;
}
tuple.clear();
for (auto& col : columns) {
auto value = col.expression()->evaluate(context);
if (context.result->has_error())
return context.result;
if (context.result->is_error())
return context.result.release_value();
tuple.append(value);
}
@ -108,39 +113,43 @@ RefPtr<SQLResult> Select::execute(ExecutionContext& context) const
sort_key.clear();
for (auto& term : m_ordering_term_list) {
auto value = term.expression()->evaluate(context);
if (context.result->has_error())
return context.result;
if (context.result->is_error())
return context.result.release_value();
sort_key.append(value);
}
}
context.result->insert(tuple, sort_key);
}
if (m_limit_clause != nullptr) {
size_t limit_value = NumericLimits<size_t>::max();
size_t offset_value = 0;
auto limit = m_limit_clause->limit_expression()->evaluate(context);
if (!limit.is_null()) {
auto limit_value_maybe = limit.to_u32();
if (!limit_value_maybe.has_value()) {
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::SyntaxError, "LIMIT clause must evaluate to an integer value");
}
if (!limit_value_maybe.has_value())
return { SQLCommand::Select, SQLErrorCode::SyntaxError, "LIMIT clause must evaluate to an integer value"sv };
limit_value = limit_value_maybe.value();
}
size_t offset_value = 0;
if (m_limit_clause->offset_expression() != nullptr) {
auto offset = m_limit_clause->offset_expression()->evaluate(context);
if (!offset.is_null()) {
auto offset_value_maybe = offset.to_u32();
if (!offset_value_maybe.has_value()) {
return SQLResult::construct(SQLCommand::Select, SQLErrorCode::SyntaxError, "OFFSET clause must evaluate to an integer value");
}
if (!offset_value_maybe.has_value())
return { SQLCommand::Select, SQLErrorCode::SyntaxError, "OFFSET clause must evaluate to an integer value"sv };
offset_value = offset_value_maybe.value();
}
}
context.result->limit(offset_value, limit_value);
}
return context.result;
return context.result.release_value();
}
}

View file

@ -11,9 +11,9 @@
namespace SQL::AST {
RefPtr<SQLResult> Statement::execute(AK::NonnullRefPtr<Database> database) const
Result Statement::execute(AK::NonnullRefPtr<Database> database) const
{
ExecutionContext context { move(database), nullptr, this, nullptr };
ExecutionContext context { move(database), {}, this, nullptr };
return execute(context);
}