Skip to content

Commit

Permalink
LibSQL+SQLServer: Build SQLServer system service
Browse files Browse the repository at this point in the history
This patch introduces the SQLServer system server. This service is
supposed to be the only process/application talking to database storage.
This makes things like locking and caching more reliable, easier to
implement, and more efficient.

In LibSQL we added a client component that does the ugly IPC nitty-
gritty for you. All that's needed is setting a number of event handler
lambdas and you can connect to databases and execute statements on them.

Applications that wish to use this SQLClient class obviously need to
link LibSQL and LibIPC.
  • Loading branch information
JanDeVisser authored and alimpfard committed Jul 8, 2021
1 parent 1037d6b commit a034774
Show file tree
Hide file tree
Showing 19 changed files with 650 additions and 12 deletions.
4 changes: 4 additions & 0 deletions AK/Debug.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@
#cmakedefine01 SQL_DEBUG
#endif

#ifndef SQLSERVER_DEBUG
#cmakedefine01 SQLSERVER_DEBUG
#endif

#ifndef SYNTAX_HIGHLIGHTING_DEBUG
#cmakedefine01 SYNTAX_HIGHLIGHTING_DEBUG
#endif
Expand Down
1 change: 1 addition & 0 deletions Meta/CMake/all_the_debug_macros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ set(SOCKET_DEBUG ON)
set(SOLITAIRE_DEBUG ON)
set(SPAM_DEBUG ON)
set(SQL_DEBUG ON)
set(SQLSERVER_DEBUG ON)
set(STORAGE_DEVICE_DEBUG ON)
set(SYNTAX_HIGHLIGHTING_DEBUG ON)
set(SYSCALL_1_DEBUG ON)
Expand Down
2 changes: 1 addition & 1 deletion Tests/LibSQL/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
file(GLOB TEST_SOURCES CONFIGURE_DEPENDS "*.cpp")

foreach(source ${TEST_SOURCES})
serenity_test(${source} LibSQL LIBS LibSQL)
serenity_test(${source} LibSQL LIBS LibSQL LibIPC)
endforeach()
6 changes: 6 additions & 0 deletions Userland/Libraries/LibSQL/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ set(SOURCES
Key.cpp
Meta.cpp
Row.cpp
SQLClient.cpp
TreeNode.cpp
Tuple.cpp
Value.cpp
)

set(GENERATED_SOURCES
../../Services/SQLServer/SQLClientEndpoint.h
../../Services/SQLServer/SQLServerEndpoint.h
)

serenity_lib(LibSQL sql)
target_link_libraries(LibSQL LibCore LibSyntax)
75 changes: 75 additions & 0 deletions Userland/Libraries/LibSQL/SQLClient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2021, Jan de Visser <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibSQL/SQLClient.h>

namespace SQL {

SQLClient::~SQLClient()
{
}

void SQLClient::connected(int connection_id)
{
if (on_connected)
on_connected(connection_id);
}

void SQLClient::disconnected(int connection_id)
{
if (on_disconnected)
on_disconnected(connection_id);
}

void SQLClient::connection_error(int connection_id, int code, String const& message)
{
if (on_connection_error)
on_connection_error(connection_id, code, message);
else
warnln("Connection error for connection_id {}: {} ({})", connection_id, message, code);
}

void SQLClient::execution_error(int statement_id, int code, String const& message)
{
if (on_execution_error)
on_execution_error(statement_id, code, message);
else
warnln("Execution error for statement_id {}: {} ({})", statement_id, message, code);
}

void SQLClient::execution_success(int statement_id, bool has_results, int created, int updated, int deleted)
{
if (on_execution_success)
on_execution_success(statement_id, has_results, created, updated, deleted);
else
outln("{} row(s) created, {} updated, {} deleted", created, updated, deleted);
}

void SQLClient::next_result(int statement_id, Vector<String> const& row)
{
if (on_next_result) {
on_next_result(statement_id, row);
return;
}
bool first = true;
for (auto& column : row) {
if (!first)
out(", ");
out("\"{}\"", column);
first = false;
}
outln();
}

void SQLClient::results_exhausted(int statement_id, int total_rows)
{
if (on_results_exhausted)
on_results_exhausted(statement_id, total_rows);
else
outln("{} total row(s)", total_rows);
}

}
44 changes: 44 additions & 0 deletions Userland/Libraries/LibSQL/SQLClient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2021, Jan de Visser <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <LibIPC/ServerConnection.h>
#include <SQLServer/SQLClientEndpoint.h>
#include <SQLServer/SQLServerEndpoint.h>

namespace SQL {

class SQLClient
: public IPC::ServerConnection<SQLClientEndpoint, SQLServerEndpoint>
, public SQLClientEndpoint {
C_OBJECT(SQLClient);
virtual ~SQLClient();

Function<void(int)> on_connected;
Function<void(int)> on_disconnected;
Function<void(int, int, String const&)> on_connection_error;
Function<void(int, int, String const&)> on_execution_error;
Function<void(int, bool, int, int, int)> on_execution_success;
Function<void(int, Vector<String> const&)> on_next_result;
Function<void(int, int)> on_results_exhausted;

private:
SQLClient()
: IPC::ServerConnection<SQLClientEndpoint, SQLServerEndpoint>(*this, "/tmp/portal/sql")
{
}

virtual void connected(int connection_id) override;
virtual void connection_error(int connection_id, int code, String const& message) override;
virtual void execution_success(int statement_id, bool has_results, int created, int updated, int deleted) override;
virtual void next_result(int statement_id, Vector<String> const&) override;
virtual void results_exhausted(int statement_id, int total_rows) override;
virtual void execution_error(int statement_id, int code, String const& message) override;
virtual void disconnected(int connection_id) override;
};

}
24 changes: 13 additions & 11 deletions Userland/Libraries/LibSQL/SQLResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,18 @@ constexpr char const* command_tag(SQLCommand command)
}
}

#define ENUMERATE_SQL_ERRORS(S) \
S(NoError, "No error") \
S(DatabaseUnavailable, "Database Unavailable") \
S(StatementUnavailable, "Statement with id {} Unavailable") \
S(SyntaxError, "Syntax Error") \
S(DatabaseDoesNotExist, "Database {} does not exist") \
S(SchemaDoesNotExist, "Schema {} does not exist") \
S(SchemaExists, "Schema {} already exist") \
S(TableDoesNotExist, "Table {} does not exist") \
S(TableExists, "Table {} already exist") \
S(InvalidType, "Invalid type {}")
#define ENUMERATE_SQL_ERRORS(S) \
S(NoError, "No error") \
S(DatabaseUnavailable, "Database Unavailable") \
S(StatementUnavailable, "Statement with id '{}' Unavailable") \
S(SyntaxError, "Syntax Error") \
S(DatabaseDoesNotExist, "Database '{}' does not exist") \
S(SchemaDoesNotExist, "Schema '{}' does not exist") \
S(SchemaExists, "Schema '{}' already exist") \
S(TableDoesNotExist, "Table '{}' does not exist") \
S(TableExists, "Table '{}' already exist") \
S(InvalidType, "Invalid type '{}'") \
S(InvalidDatabaseName, "Invalid database name '{}'")

enum class SQLErrorCode {
#undef __ENUMERATE_SQL_ERROR
Expand Down Expand Up @@ -120,6 +121,7 @@ class SQLResult : public Core::Object {
, m_update_count(update_count)
, m_insert_count(insert_count)
, m_delete_count(delete_count)
, m_has_results(command == SQLCommand::Select)
{
}

Expand Down
1 change: 1 addition & 0 deletions Userland/Services/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_subdirectory(LaunchServer)
add_subdirectory(LookupServer)
add_subdirectory(NotificationServer)
add_subdirectory(RequestServer)
add_subdirectory(SQLServer)
add_subdirectory(SystemServer)
add_subdirectory(Taskbar)
add_subdirectory(TelnetServer)
Expand Down
20 changes: 20 additions & 0 deletions Userland/Services/SQLServer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
serenity_component(
SQLServer
REQUIRED
TARGETS SQLServer
)

compile_ipc(SQLServer.ipc SQLServerEndpoint.h)
compile_ipc(SQLClient.ipc SQLClientEndpoint.h)

set(SOURCES
ClientConnection.cpp
DatabaseConnection.cpp
main.cpp
SQLClientEndpoint.h
SQLServerEndpoint.h
SQLStatement.cpp
)

serenity_bin(SQLServer)
target_link_libraries(SQLServer LibCore LibIPC LibSQL)
84 changes: 84 additions & 0 deletions Userland/Services/SQLServer/ClientConnection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2021, Jan de Visser <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <AK/String.h>
#include <AK/Vector.h>
#include <LibSQL/SQLResult.h>
#include <SQLServer/ClientConnection.h>
#include <SQLServer/DatabaseConnection.h>
#include <SQLServer/SQLStatement.h>

namespace SQLServer {

static HashMap<int, RefPtr<ClientConnection>> s_connections;

RefPtr<ClientConnection> ClientConnection::client_connection_for(int client_id)
{
if (s_connections.contains(client_id))
return *s_connections.get(client_id).value();
dbgln_if(SQLSERVER_DEBUG, "Invalid client_id {}", client_id);
return nullptr;
}

ClientConnection::ClientConnection(AK::NonnullRefPtr<Core::LocalSocket> socket, int client_id)
: IPC::ClientConnection<SQLClientEndpoint, SQLServerEndpoint>(*this, move(socket), client_id)
{
s_connections.set(client_id, *this);
}

ClientConnection::~ClientConnection()
{
}

void ClientConnection::die()
{
s_connections.remove(client_id());
}

Messages::SQLServer::ConnectResponse ClientConnection::connect(String const& database_name)
{
dbgln_if(SQLSERVER_DEBUG, "ClientConnection::connect(database_name: {})", database_name);
auto database_connection = DatabaseConnection::construct(database_name, client_id());
return { database_connection->connection_id() };
}

void ClientConnection::disconnect(int connection_id)
{
dbgln_if(SQLSERVER_DEBUG, "ClientConnection::disconnect(connection_id: {})", connection_id);
auto database_connection = DatabaseConnection::connection_for(connection_id);
if (database_connection)
database_connection->disconnect();
else
dbgln("Database connection has disappeared");
}

Messages::SQLServer::SqlStatementResponse ClientConnection::sql_statement(int connection_id, String const& sql)
{
dbgln_if(SQLSERVER_DEBUG, "ClientConnection::sql_statement(connection_id: {}, sql: '{}')", connection_id, sql);
auto database_connection = DatabaseConnection::connection_for(connection_id);
if (database_connection) {
auto statement_id = database_connection->sql_statement(sql);
dbgln_if(SQLSERVER_DEBUG, "ClientConnection::sql_statement -> statement_id = {}", statement_id);
return { statement_id };
} else {
dbgln("Database connection has disappeared");
return { -1 };
}
}

void ClientConnection::statement_execute(int statement_id)
{
dbgln_if(SQLSERVER_DEBUG, "ClientConnection::statement_execute_query(statement_id: {})", statement_id);
auto statement = SQLStatement::statement_for(statement_id);
if (statement && statement->connection()->client_id() == client_id()) {
statement->execute();
} else {
dbgln_if(SQLSERVER_DEBUG, "Statement has disappeared");
async_execution_error(statement_id, (int)SQL::SQLErrorCode::StatementUnavailable, String::formatted("{}", statement_id));
}
}

}
35 changes: 35 additions & 0 deletions Userland/Services/SQLServer/ClientConnection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2021, Jan de Visser <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/HashMap.h>
#include <LibIPC/ClientConnection.h>
#include <SQLServer/SQLClientEndpoint.h>
#include <SQLServer/SQLServerEndpoint.h>

namespace SQLServer {

class ClientConnection final
: public IPC::ClientConnection<SQLClientEndpoint, SQLServerEndpoint> {
C_OBJECT(ClientConnection);

public:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
virtual ~ClientConnection() override;

virtual void die() override;

static RefPtr<ClientConnection> client_connection_for(int client_id);

private:
virtual Messages::SQLServer::ConnectResponse connect(String const&) override;
virtual Messages::SQLServer::SqlStatementResponse sql_statement(int, String const&) override;
virtual void statement_execute(int) override;
virtual void disconnect(int) override;
};

}
Loading

0 comments on commit a034774

Please sign in to comment.