summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibSQL
diff options
context:
space:
mode:
authorJan de Visser <jan@de-visser.net>2021-09-16 22:29:19 +0200
committerAndreas Kling <kling@serenityos.org>2021-10-05 02:22:19 +0200
commitfe50598a03e30d4946a8b67c51ec9c5f391a3e44 (patch)
tree6aea339f4dcff0bc69ea7edacaf0cfa6b2f8c9a6 /Userland/Libraries/LibSQL
parentf33a288ca48dc488f08363437d0732d52363eca1 (diff)
downloadserenity-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.h3
-rw-r--r--Userland/Libraries/LibSQL/AST/Expression.cpp13
-rw-r--r--Userland/Libraries/LibSQL/AST/Select.cpp38
-rw-r--r--Userland/Libraries/LibSQL/Tuple.cpp5
-rw-r--r--Userland/Libraries/LibSQL/Tuple.h2
-rw-r--r--Userland/Libraries/LibSQL/TupleDescriptor.h14
-rw-r--r--Userland/Libraries/LibSQL/Type.h24
-rw-r--r--Userland/Libraries/LibSQL/Value.h5
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 = {});