1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 10:44:58 +00:00
serenity/Userland/Services/SQLServer/SQLStatement.cpp
sin-ack 8ea22121ac Userland: Migrate to argument-less deferred_invoke
Only one place used this argument and it was to hold on to a strong ref
for the object. Since we already do that now, there's no need to keep
this argument around since this can be easily captured.

This commit contains no changes.
2021-09-02 03:47:47 +04:30

118 lines
4 KiB
C++

/*
* Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/Object.h>
#include <LibSQL/AST/Parser.h>
#include <SQLServer/ClientConnection.h>
#include <SQLServer/DatabaseConnection.h>
#include <SQLServer/SQLStatement.h>
namespace SQLServer {
static HashMap<int, NonnullRefPtr<SQLStatement>> s_statements;
RefPtr<SQLStatement> SQLStatement::statement_for(int statement_id)
{
if (s_statements.contains(statement_id))
return *s_statements.get(statement_id).value();
dbgln_if(SQLSERVER_DEBUG, "Invalid statement_id {}", statement_id);
return nullptr;
}
static int s_next_statement_id = 0;
SQLStatement::SQLStatement(DatabaseConnection& connection, String sql)
: Core::Object(&connection)
, m_statement_id(s_next_statement_id++)
, m_sql(move(sql))
{
dbgln_if(SQLSERVER_DEBUG, "SQLStatement({}, {})", connection.connection_id(), sql);
s_statements.set(m_statement_id, *this);
}
void SQLStatement::report_error(SQL::SQLError error)
{
dbgln_if(SQLSERVER_DEBUG, "SQLStatement::report_error(statement_id {}, error {}", statement_id(), error.to_string());
auto client_connection = ClientConnection::client_connection_for(connection()->client_id());
m_statement = nullptr;
m_result = nullptr;
remove_from_parent();
s_statements.remove(statement_id());
if (!client_connection) {
warnln("Cannot return execution error. Client disconnected");
warnln("SQLStatement::report_error(statement_id {}, error {}", statement_id(), error.to_string());
m_result = nullptr;
return;
}
client_connection->async_execution_error(statement_id(), (int)error.code, error.to_string());
m_result = nullptr;
}
void SQLStatement::execute()
{
dbgln_if(SQLSERVER_DEBUG, "SQLStatement::execute(statement_id {}", statement_id());
auto client_connection = ClientConnection::client_connection_for(connection()->client_id());
if (!client_connection) {
warnln("Cannot yield next result. Client disconnected");
return;
}
deferred_invoke([&] {
auto maybe_error = parse();
if (maybe_error.has_value()) {
report_error(maybe_error.value());
return;
}
VERIFY(!connection()->database().is_null());
SQL::AST::ExecutionContext context { connection()->database().release_nonnull() };
m_result = m_statement->execute(context);
if (m_result->error().code != SQL::SQLErrorCode::NoError) {
report_error(m_result->error());
return;
}
auto client_connection = ClientConnection::client_connection_for(connection()->client_id());
if (!client_connection) {
warnln("Cannot return statement execution results. Client disconnected");
return;
}
client_connection->async_execution_success(statement_id(), m_result->has_results(), m_result->updated(), m_result->inserted(), m_result->deleted());
if (m_result->has_results()) {
m_index = 0;
next();
}
});
}
Optional<SQL::SQLError> SQLStatement::parse()
{
auto parser = SQL::AST::Parser(SQL::AST::Lexer(m_sql));
m_statement = parser.next_statement();
if (parser.has_errors()) {
return SQL::SQLError { SQL::SQLErrorCode::SyntaxError, parser.errors()[0].to_string() };
}
return {};
}
void SQLStatement::next()
{
VERIFY(m_result->has_results());
auto client_connection = ClientConnection::client_connection_for(connection()->client_id());
if (!client_connection) {
warnln("Cannot yield next result. Client disconnected");
return;
}
if (m_index < m_result->results().size()) {
auto& tuple = m_result->results()[m_index++];
client_connection->async_next_result(statement_id(), tuple.to_string_vector());
deferred_invoke([&] {
next();
});
} else {
client_connection->async_results_exhausted(statement_id(), (int)m_index);
}
}
}