Serenity Operating System
at master 183 lines 6.6 kB view raw
1/* 2 * Copyright (c) 2021, Jan de Visser <jan@de-visser.net> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/NumericLimits.h> 8#include <LibSQL/AST/AST.h> 9#include <LibSQL/Database.h> 10#include <LibSQL/Meta.h> 11#include <LibSQL/Row.h> 12 13namespace SQL::AST { 14 15static DeprecatedString result_column_name(ResultColumn const& column, size_t column_index) 16{ 17 auto fallback_column_name = [column_index]() { 18 return DeprecatedString::formatted("Column{}", column_index); 19 }; 20 21 if (auto const& alias = column.column_alias(); !alias.is_empty()) 22 return alias; 23 24 if (column.select_from_expression()) { 25 if (is<ColumnNameExpression>(*column.expression())) { 26 auto const& column_name_expression = verify_cast<ColumnNameExpression>(*column.expression()); 27 return column_name_expression.column_name(); 28 } 29 30 // FIXME: Generate column names from other result column expressions. 31 return fallback_column_name(); 32 } 33 34 VERIFY(column.select_from_table()); 35 36 // FIXME: Generate column names from select-from-table result columns. 37 return fallback_column_name(); 38} 39 40ResultOr<ResultSet> Select::execute(ExecutionContext& context) const 41{ 42 Vector<NonnullRefPtr<ResultColumn const>> columns; 43 Vector<DeprecatedString> column_names; 44 45 auto const& result_column_list = this->result_column_list(); 46 VERIFY(!result_column_list.is_empty()); 47 48 for (auto& table_descriptor : table_or_subquery_list()) { 49 if (!table_descriptor->is_table()) 50 return Result { SQLCommand::Select, SQLErrorCode::NotYetImplemented, "Sub-selects are not yet implemented"sv }; 51 52 auto table_def = TRY(context.database->get_table(table_descriptor->schema_name(), table_descriptor->table_name())); 53 54 if (result_column_list.size() == 1 && result_column_list[0]->type() == ResultType::All) { 55 TRY(columns.try_ensure_capacity(columns.size() + table_def->columns().size())); 56 TRY(column_names.try_ensure_capacity(column_names.size() + table_def->columns().size())); 57 58 for (auto& col : table_def->columns()) { 59 columns.unchecked_append( 60 create_ast_node<ResultColumn>( 61 create_ast_node<ColumnNameExpression>(table_def->parent()->name(), table_def->name(), col->name()), 62 "")); 63 64 column_names.unchecked_append(col->name()); 65 } 66 } 67 } 68 69 if (result_column_list.size() != 1 || result_column_list[0]->type() != ResultType::All) { 70 TRY(columns.try_ensure_capacity(result_column_list.size())); 71 TRY(column_names.try_ensure_capacity(result_column_list.size())); 72 73 for (size_t i = 0; i < result_column_list.size(); ++i) { 74 auto const& col = result_column_list[i]; 75 76 if (col->type() == ResultType::All) { 77 // FIXME can have '*' for example in conjunction with computed columns 78 return Result { SQLCommand::Select, SQLErrorCode::SyntaxError, "*"sv }; 79 } 80 81 columns.unchecked_append(col); 82 column_names.unchecked_append(result_column_name(col, i)); 83 } 84 } 85 86 ResultSet result { SQLCommand::Select, move(column_names) }; 87 88 auto descriptor = adopt_ref(*new TupleDescriptor); 89 Tuple tuple(descriptor); 90 Vector<Tuple> rows; 91 descriptor->empend("__unity__"sv); 92 tuple.append(Value { true }); 93 rows.append(tuple); 94 95 for (auto& table_descriptor : table_or_subquery_list()) { 96 if (!table_descriptor->is_table()) 97 return Result { SQLCommand::Select, SQLErrorCode::NotYetImplemented, "Sub-selects are not yet implemented"sv }; 98 99 auto table_def = TRY(context.database->get_table(table_descriptor->schema_name(), table_descriptor->table_name())); 100 if (table_def->num_columns() == 0) 101 continue; 102 103 auto old_descriptor_size = descriptor->size(); 104 descriptor->extend(table_def->to_tuple_descriptor()); 105 106 while (!rows.is_empty() && (rows.first().size() == old_descriptor_size)) { 107 auto cartesian_row = rows.take_first(); 108 auto table_rows = TRY(context.database->select_all(*table_def)); 109 110 for (auto& table_row : table_rows) { 111 auto new_row = cartesian_row; 112 new_row.extend(table_row); 113 rows.append(new_row); 114 } 115 } 116 } 117 118 bool has_ordering { false }; 119 auto sort_descriptor = adopt_ref(*new TupleDescriptor); 120 for (auto& term : m_ordering_term_list) { 121 sort_descriptor->append(TupleElementDescriptor { .order = term->order() }); 122 has_ordering = true; 123 } 124 Tuple sort_key(sort_descriptor); 125 126 for (auto& row : rows) { 127 context.current_row = &row; 128 129 if (where_clause()) { 130 auto where_result = TRY(where_clause()->evaluate(context)).to_bool(); 131 if (!where_result.has_value() || !where_result.value()) 132 continue; 133 } 134 135 tuple.clear(); 136 137 for (auto& col : columns) { 138 auto value = TRY(col->expression()->evaluate(context)); 139 tuple.append(value); 140 } 141 142 if (has_ordering) { 143 sort_key.clear(); 144 for (auto& term : m_ordering_term_list) { 145 auto value = TRY(term->expression()->evaluate(context)); 146 sort_key.append(value); 147 } 148 } 149 150 result.insert_row(tuple, sort_key); 151 } 152 153 if (m_limit_clause != nullptr) { 154 size_t limit_value = NumericLimits<size_t>::max(); 155 size_t offset_value = 0; 156 157 auto limit = TRY(m_limit_clause->limit_expression()->evaluate(context)); 158 if (!limit.is_null()) { 159 auto limit_value_maybe = limit.to_int<size_t>(); 160 if (!limit_value_maybe.has_value()) 161 return Result { SQLCommand::Select, SQLErrorCode::SyntaxError, "LIMIT clause must evaluate to an integer value"sv }; 162 163 limit_value = limit_value_maybe.value(); 164 } 165 166 if (m_limit_clause->offset_expression() != nullptr) { 167 auto offset = TRY(m_limit_clause->offset_expression()->evaluate(context)); 168 if (!offset.is_null()) { 169 auto offset_value_maybe = offset.to_int<size_t>(); 170 if (!offset_value_maybe.has_value()) 171 return Result { SQLCommand::Select, SQLErrorCode::SyntaxError, "OFFSET clause must evaluate to an integer value"sv }; 172 173 offset_value = offset_value_maybe.value(); 174 } 175 } 176 177 result.limit(offset_value, limit_value); 178 } 179 180 return result; 181} 182 183}