diff options
author | Jan de Visser <jan@de-visser.net> | 2021-09-16 22:29:19 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-10-05 02:22:19 +0200 |
commit | fe50598a03e30d4946a8b67c51ec9c5f391a3e44 (patch) | |
tree | 6aea339f4dcff0bc69ea7edacaf0cfa6b2f8c9a6 /Userland/Libraries/LibSQL | |
parent | f33a288ca48dc488f08363437d0732d52363eca1 (diff) | |
download | serenity-fe50598a03e30d4946a8b67c51ec9c5f391a3e44.zip |
LibSQL: Allow expressions and column names in SELECT ... FROM
Up to now the only ``SELECT`` statement that worked was ``SELECT *
FROM <table>``. This commit allows a column list consisting of
column names and expressions in addition to ``*``. ``WHERE``
still doesn't work though.
Diffstat (limited to 'Userland/Libraries/LibSQL')
-rw-r--r-- | Userland/Libraries/LibSQL/AST/AST.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/AST/Expression.cpp | 13 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/AST/Select.cpp | 38 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/Tuple.cpp | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/Tuple.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/TupleDescriptor.h | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/Type.h | 24 | ||||
-rw-r--r-- | Userland/Libraries/LibSQL/Value.h | 5 |
8 files changed, 87 insertions, 17 deletions
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> database; RefPtr<SQLResult> 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<SQLResult> Select::execute(ExecutionContext& context) const { if (table_or_subquery_list().size() == 1 && table_or_subquery_list()[0].is_table()) { + 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<ResultColumn> columns; 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()); + for (auto& col : table->columns()) { + columns.append( + create_ast_node<ResultColumn>( + create_ast_node<ColumnNameExpression>(table->parent()->name(), table->name(), col.name()), + "")); } - NonnullRefPtr<TupleDescriptor> 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); + } else { + for (auto& col : result_column_list()) { + columns.append(col); + } + } + context.result = SQLResult::construct(); + AK::NonnullRefPtr<TupleDescriptor> 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); } - return context.result; + 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<TupleDescriptor> 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<String> elements; + for (auto& element : *this) { + elements.append(element.to_string()); + } + return String::formatted("[\n{}\n]", String::join("\n", elements)); + } + using Vector<TupleElementDescriptor>::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<TupleDescriptor> const&); static Value create_array(SQLType element_type, Optional<size_t> const& max_size = {}); |