diff --git a/Userland/Libraries/LibSQL/AST/AST.h b/Userland/Libraries/LibSQL/AST/AST.h index 7a8ca428eb..168a61bb1d 100644 --- a/Userland/Libraries/LibSQL/AST/AST.h +++ b/Userland/Libraries/LibSQL/AST/AST.h @@ -298,7 +298,7 @@ private: struct ExecutionContext { NonnullRefPtr database; RefPtr result { nullptr }; - Tuple current_row {}; + Tuple* current_row { nullptr }; }; class Expression : public ASTNode { @@ -429,6 +429,7 @@ public: const String& schema_name() const { return m_schema_name; } const String& table_name() const { return m_table_name; } const String& column_name() const { return m_column_name; } + virtual Value evaluate(ExecutionContext&) const override; private: String m_schema_name; diff --git a/Userland/Libraries/LibSQL/AST/Expression.cpp b/Userland/Libraries/LibSQL/AST/Expression.cpp index a66257fb41..c9c20d2892 100644 --- a/Userland/Libraries/LibSQL/AST/Expression.cpp +++ b/Userland/Libraries/LibSQL/AST/Expression.cpp @@ -87,4 +87,17 @@ Value UnaryOperatorExpression::evaluate(ExecutionContext& context) const VERIFY_NOT_REACHED(); } +Value ColumnNameExpression::evaluate(ExecutionContext& context) const +{ + auto& descriptor = *context.current_row->descriptor(); + VERIFY(context.current_row->size() == descriptor.size()); + for (auto ix = 0u; ix < context.current_row->size(); ix++) { + auto& column_descriptor = descriptor[ix]; + if (column_descriptor.name == column_name()) + return { (*context.current_row)[ix] }; + } + // TODO: Error handling. + VERIFY_NOT_REACHED(); +} + } diff --git a/Userland/Libraries/LibSQL/AST/Select.cpp b/Userland/Libraries/LibSQL/AST/Select.cpp index 4239497e49..c350ffee65 100644 --- a/Userland/Libraries/LibSQL/AST/Select.cpp +++ b/Userland/Libraries/LibSQL/AST/Select.cpp @@ -14,22 +14,36 @@ namespace SQL::AST { RefPtr Select::execute(ExecutionContext& context) const { if (table_or_subquery_list().size() == 1 && table_or_subquery_list()[0].is_table()) { - if (result_column_list().size() == 1 && result_column_list()[0].type() == ResultType::All) { - auto table = context.database->get_table(table_or_subquery_list()[0].schema_name(), table_or_subquery_list()[0].table_name()); - if (!table) { - return SQLResult::construct(SQL::SQLCommand::Select, SQL::SQLErrorCode::TableDoesNotExist, table_or_subquery_list()[0].table_name()); - } - NonnullRefPtr descriptor = table->to_tuple_descriptor(); - context.result = SQLResult::construct(); - for (auto& row : context.database->select_all(*table)) { - Tuple tuple(descriptor); - for (auto ix = 0u; ix < descriptor->size(); ix++) { - tuple[ix] = row[ix]; - } - context.result->append(tuple); - } - return context.result; + auto table = context.database->get_table(table_or_subquery_list()[0].schema_name(), table_or_subquery_list()[0].table_name()); + if (!table) { + return SQLResult::construct(SQL::SQLCommand::Select, SQL::SQLErrorCode::TableDoesNotExist, table_or_subquery_list()[0].table_name()); } + + NonnullRefPtrVector columns; + if (result_column_list().size() == 1 && result_column_list()[0].type() == ResultType::All) { + for (auto& col : table->columns()) { + columns.append( + create_ast_node( + create_ast_node(table->parent()->name(), table->name(), col.name()), + "")); + } + } else { + for (auto& col : result_column_list()) { + columns.append(col); + } + } + context.result = SQLResult::construct(); + AK::NonnullRefPtr descriptor = AK::adopt_ref(*new TupleDescriptor); + for (auto& row : context.database->select_all(*table)) { + context.current_row = &row; + Tuple tuple(descriptor); + for (auto& col : columns) { + auto value = col.expression()->evaluate(context); + tuple.append(value); + } + context.result->append(tuple); + } + return context.result; } return SQLResult::construct(); } diff --git a/Userland/Libraries/LibSQL/Tuple.cpp b/Userland/Libraries/LibSQL/Tuple.cpp index 96d98ae906..8e64b9478c 100644 --- a/Userland/Libraries/LibSQL/Tuple.cpp +++ b/Userland/Libraries/LibSQL/Tuple.cpp @@ -119,7 +119,10 @@ Value& Tuple::operator[](String const& name) void Tuple::append(const Value& value) { - VERIFY(m_descriptor->size() == 0); + VERIFY(descriptor()->size() >= size()); + if (descriptor()->size() == size()) { + descriptor()->append(value.descriptor()); + } m_data.append(value); } diff --git a/Userland/Libraries/LibSQL/Tuple.h b/Userland/Libraries/LibSQL/Tuple.h index 8831fe88db..9ae1530b2e 100644 --- a/Userland/Libraries/LibSQL/Tuple.h +++ b/Userland/Libraries/LibSQL/Tuple.h @@ -62,7 +62,7 @@ public: [[nodiscard]] size_t size() const { return m_data.size(); } [[nodiscard]] virtual size_t length() const; - void clear() { m_descriptor->clear(); } + void clear() { m_data.clear(); } [[nodiscard]] NonnullRefPtr descriptor() const { return m_descriptor; } [[nodiscard]] int compare(Tuple const&) const; [[nodiscard]] int match(Tuple const&) const; diff --git a/Userland/Libraries/LibSQL/TupleDescriptor.h b/Userland/Libraries/LibSQL/TupleDescriptor.h index ddbb68830b..a4ca1cc6b8 100644 --- a/Userland/Libraries/LibSQL/TupleDescriptor.h +++ b/Userland/Libraries/LibSQL/TupleDescriptor.h @@ -36,6 +36,11 @@ struct TupleElementDescriptor { { return (sizeof(u32) + name.length()) + 2 * sizeof(u8); } + + String to_string() const + { + return String::formatted(" name: {} type: {} order: {}", name, SQLType_name(type), Order_name(order)); + } }; class TupleDescriptor @@ -84,6 +89,15 @@ public: return len; } + String to_string() const + { + Vector elements; + for (auto& element : *this) { + elements.append(element.to_string()); + } + return String::formatted("[\n{}\n]", String::join("\n", elements)); + } + using Vector::operator==; }; diff --git a/Userland/Libraries/LibSQL/Type.h b/Userland/Libraries/LibSQL/Type.h index fd4b32f21e..fb20e42e67 100644 --- a/Userland/Libraries/LibSQL/Type.h +++ b/Userland/Libraries/LibSQL/Type.h @@ -55,11 +55,31 @@ inline static size_t size_of(SQLType t) } } +#define ENUMERATE_ORDERS(S) \ + S(Ascending) \ + S(Descending) + enum class Order { - Ascending, - Descending, +#undef __ENUMERATE_ORDER +#define __ENUMERATE_ORDER(order) order, + ENUMERATE_ORDERS(__ENUMERATE_ORDER) +#undef __ENUMERATE_ORDER }; +inline static String Order_name(Order order) +{ + switch (order) { +#undef __ENUMERATE_ORDER +#define __ENUMERATE_ORDER(order) \ + case Order::order: \ + return #order; + ENUMERATE_ORDERS(__ENUMERATE_ORDER) +#undef __ENUMERATE_ORDER + default: + VERIFY_NOT_REACHED(); + } +} + enum class Nulls { First, Last, diff --git a/Userland/Libraries/LibSQL/Value.h b/Userland/Libraries/LibSQL/Value.h index 76233c4248..4f10ca2804 100644 --- a/Userland/Libraries/LibSQL/Value.h +++ b/Userland/Libraries/LibSQL/Value.h @@ -116,6 +116,11 @@ public: bool operator>(Value const&) const; bool operator>=(Value const&) const; + [[nodiscard]] TupleElementDescriptor descriptor() const + { + return { "", type(), Order::Ascending }; + } + static Value const& null(); static Value create_tuple(NonnullRefPtr const&); static Value create_array(SQLType element_type, Optional const& max_size = {});