mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 12:54:58 +00:00

Data types are now checked against the table data types. When multiple rows are inserted at once, we check all rows to be matching W.R.T data types. Only then we insert the rows.
84 lines
3 KiB
C++
84 lines
3 KiB
C++
/*
|
|
* Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
|
|
* Copyright (c) 2021, Mahmoud Mandour <ma.mandourr@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibSQL/AST/AST.h>
|
|
#include <LibSQL/Database.h>
|
|
#include <LibSQL/Meta.h>
|
|
#include <LibSQL/Row.h>
|
|
|
|
namespace SQL::AST {
|
|
|
|
static bool does_value_data_type_match(SQLType expected, SQLType actual)
|
|
{
|
|
if (actual == SQLType::Null) {
|
|
return false;
|
|
}
|
|
|
|
if (expected == SQLType::Integer) {
|
|
return actual == SQLType::Integer || actual == SQLType::Float;
|
|
}
|
|
|
|
return expected == actual;
|
|
}
|
|
|
|
RefPtr<SQLResult> Insert::execute(ExecutionContext& context) const
|
|
{
|
|
auto table_def = 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));
|
|
}
|
|
|
|
Row row(table_def);
|
|
for (auto& column : m_column_names) {
|
|
if (!row.has(column)) {
|
|
return SQLResult::construct(SQLCommand::Insert, SQLErrorCode::ColumnDoesNotExist, column);
|
|
}
|
|
}
|
|
|
|
Vector<Row> inserted_rows;
|
|
inserted_rows.ensure_capacity(m_chained_expressions.size());
|
|
for (auto& row_expr : m_chained_expressions) {
|
|
for (auto& column_def : table_def->columns()) {
|
|
if (!m_column_names.contains_slow(column_def.name())) {
|
|
row[column_def.name()] = column_def.default_value();
|
|
}
|
|
}
|
|
auto row_value = row_expr.evaluate(context);
|
|
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, "");
|
|
}
|
|
|
|
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_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());
|
|
}
|
|
|
|
row[element_index] = values[ix];
|
|
}
|
|
inserted_rows.append(row);
|
|
}
|
|
|
|
for (auto& inserted_row : inserted_rows) {
|
|
context.database->insert(inserted_row);
|
|
}
|
|
|
|
return SQLResult::construct(SQLCommand::Insert, 0, m_chained_expressions.size(), 0);
|
|
}
|
|
|
|
}
|