1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:55:08 +00:00
serenity/Userland/Services/SQLServer/DatabaseConnection.cpp
Timothy Flynn 56843baff9 LibSQL+SQLServer: Return a NonnullRefPtr from Database::get_schema
Database::get_schema currently either returns a RefPtr to an existing
schema, a nullptr if the schema doesn't exist, or an Error if some
internal error occured. Change this to return a NonnullRefPtr to an
exisiting schema, or a SQL::Result with any error, including if the
schema was not found. Callers can then handle that specific error code
if they want.

Returning a NonnullRefPtr will enable some further cleanup. This had
some fallout of needing to change some other methods' return types from
AK::ErrorOr to SQL::Result so that TRY may continue to be used.
2022-11-30 11:43:13 +01:00

86 lines
3.4 KiB
C++

/*
* Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/LexicalPath.h>
#include <SQLServer/ConnectionFromClient.h>
#include <SQLServer/DatabaseConnection.h>
#include <SQLServer/SQLStatement.h>
namespace SQLServer {
static HashMap<int, NonnullRefPtr<DatabaseConnection>> s_connections;
RefPtr<DatabaseConnection> DatabaseConnection::connection_for(int connection_id)
{
if (s_connections.contains(connection_id))
return *s_connections.get(connection_id).value();
dbgln_if(SQLSERVER_DEBUG, "Invalid connection_id {}", connection_id);
return nullptr;
}
static int s_next_connection_id = 0;
DatabaseConnection::DatabaseConnection(String database_name, int client_id)
: Object()
, m_database_name(move(database_name))
, m_connection_id(s_next_connection_id++)
, m_client_id(client_id)
{
if (LexicalPath path(m_database_name); (path.title() != m_database_name) || (path.dirname() != ".")) {
auto client_connection = ConnectionFromClient::client_connection_for(m_client_id);
client_connection->async_connection_error(m_connection_id, (int)SQL::SQLErrorCode::InvalidDatabaseName, m_database_name);
return;
}
dbgln_if(SQLSERVER_DEBUG, "DatabaseConnection {} initiating connection with database '{}'", connection_id(), m_database_name);
s_connections.set(m_connection_id, *this);
deferred_invoke([this]() {
m_database = SQL::Database::construct(String::formatted("/home/anon/sql/{}.db", m_database_name));
auto client_connection = ConnectionFromClient::client_connection_for(m_client_id);
if (auto maybe_error = m_database->open(); maybe_error.is_error()) {
client_connection->async_connection_error(m_connection_id, to_underlying(maybe_error.error().error()), maybe_error.error().error_string());
return;
}
m_accept_statements = true;
if (client_connection)
client_connection->async_connected(m_connection_id, m_database_name);
else
warnln("Cannot notify client of database connection. Client disconnected");
});
}
void DatabaseConnection::disconnect()
{
dbgln_if(SQLSERVER_DEBUG, "DatabaseConnection::disconnect(connection_id {}, database '{}'", connection_id(), m_database_name);
m_accept_statements = false;
deferred_invoke([this]() {
m_database = nullptr;
s_connections.remove(m_connection_id);
auto client_connection = ConnectionFromClient::client_connection_for(client_id());
if (client_connection)
client_connection->async_disconnected(m_connection_id);
else
warnln("Cannot notify client of database disconnection. Client disconnected");
});
}
int DatabaseConnection::prepare_statement(String const& sql)
{
dbgln_if(SQLSERVER_DEBUG, "DatabaseConnection::prepare_statement(connection_id {}, database '{}', sql '{}'", connection_id(), m_database_name, sql);
auto client_connection = ConnectionFromClient::client_connection_for(client_id());
if (!client_connection) {
warnln("Cannot notify client of database disconnection. Client disconnected");
return -1;
}
if (!m_accept_statements) {
client_connection->async_execution_error(-1, (int)SQL::SQLErrorCode::DatabaseUnavailable, m_database_name);
return -1;
}
auto statement = SQLStatement::construct(*this, sql);
return statement->statement_id();
}
}