Files
HL2Overcharged/game/client/overcharged/DB_Handler/dbhandler.cpp
2025-05-21 21:09:22 +03:00

301 lines
7.1 KiB
C++

#include "cbase.h"
#include "dbhandler.h"
#include "tier0/icommandline.h"
#include "filesystem.h"
void DebugDatabase_ChangeCallback(IConVar *pConVar, char const *pOldString, float flOldValue);
ConVar debug_database("debug_database", "0", FCVAR_CHEAT, "Show all database commands in the server console", true, 0, true, 1, DebugDatabase_ChangeCallback);
void DebugDatabase_ChangeCallback(IConVar *pConVar, char const *pOldString, float flOldValue)
{
db()->EnableDebugging(debug_database.GetInt() == 1);
}
#ifndef CLIENT_DLL
#define VarArgs UTIL_VarArgs
#endif
dbHandler* g_pDB;
dbHandler::dbHandler()
{
m_bIsDebugging = false;
m_iInTransaction = 0;
}
dbHandler::~dbHandler()
{
sqlite3_close(db);
if (m_bIsDebugging)
Msg("database connection closed\n");
}
// returns true if the database already existed, false otherwise (it will be created in this case)
void dbHandler::Initialise(const char *filename)
{
//filesystem->FileExists(filename, "MOD");
g_pDB = new dbHandler();
int rc = sqlite3_open(VarArgs("%s\\%s", CommandLine()->ParmValue("-game", "hl2"), filename), g_pDB->Reference());
if (rc && g_pDB->m_bIsDebugging)
Msg("Failed to open database: %s\n", sqlite3_errmsg(g_pDB->Instance()));
}
void dbHandler::ShowError(int returnCode, const char *action, const char *command, const char *customError)
{
Warning(VarArgs("Database error #%i when %s command:\n%s\nError message: %s\n", returnCode, action, command, customError == NULL ? sqlite3_errmsg(db) : customError));
}
void dbHandler::BeginTransaction()
{
m_iInTransaction++;
if (m_iInTransaction == 1)
{
bool bDebugging = m_bIsDebugging;
m_bIsDebugging = false; // don't write out BEGIN / COMMIT commands
Command("BEGIN");
m_bIsDebugging = bDebugging;
}
}
void dbHandler::CommitTransaction()
{
m_iInTransaction = min(m_iInTransaction - 1, 0);
if (m_iInTransaction == 0)
{
bool bDebugging = m_bIsDebugging;
m_bIsDebugging = false; // don't write out BEGIN / COMMIT commands
Command("COMMIT");
m_bIsDebugging = bDebugging;
}
}
// execute a command that outputs no data, returns true on success or false on failure
bool dbHandler::Command(const char *cmd, ...)
{
va_list marker;
char msg[4096];
va_start(marker, cmd);
Q_vsnprintf(msg, sizeof(msg), cmd, marker);
va_end(marker);
const char *command = VarArgs(msg);
if (m_bIsDebugging)
Msg("%s\n", command);
bool retVal = true;
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, command, -1, &stmt, 0);
if (rc)
{
ShowError(rc, "preparing", command);
retVal = false;
}
else
{
rc = sqlite3_step(stmt);
switch (rc)
{
case SQLITE_DONE:
case SQLITE_OK:
break;
default:
ShowError(rc, "processing", command);
retVal = false;
break;
}
// finalize the statement to release resources
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK)
ShowError(rc, "finalising", command);
}
return retVal;
}
const char* dbHandler::ReadString(const char *cmd, ...)
{
va_list marker;
char msg[4096];
va_start(marker, cmd);
Q_vsnprintf(msg, sizeof(msg), cmd, marker);
va_end(marker);
const char *command = VarArgs(msg);
if (m_bIsDebugging)
Msg("%s\n", command);
bool isnull = true;
char retVal[MAX_DB_STRING];
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, command, -1, &stmt, 0);
if (rc)
ShowError(rc, "preparing", command);
else
{
//int cols = sqlite3_column_count(stmt);
do
{
rc = sqlite3_step(stmt);
switch (rc)
{
case SQLITE_DONE:
case SQLITE_OK:
break;
case SQLITE_ROW:
// print results for this row, the only row (hopefully)
Q_snprintf(retVal, sizeof(retVal), (const char*)sqlite3_column_text(stmt, 0));
isnull = false;
break;
default:
ShowError(rc, "processing", command);
break;
}
} while (rc == SQLITE_ROW);
// finalize the statement to release resources
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK)
ShowError(rc, "finalising", command);
}
if (m_bIsDebugging)
Msg("returning: %s\n", isnull ? "null" : retVal);
return isnull ? NULL : retVal;
}
int dbHandler::ReadInt(const char *cmd, ...)
{
va_list marker;
char msg[4096];
va_start(marker, cmd);
Q_vsnprintf(msg, sizeof(msg), cmd, marker);
va_end(marker);
const char *command = VarArgs(msg);
if (m_bIsDebugging)
Msg("%s\n", command);
int retVal = -1;
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, command, -1, &stmt, 0);
if (rc != SQLITE_OK)
ShowError(rc, "preparing", command);
else
{
//int cols = sqlite3_column_count(stmt);
do
{
rc = sqlite3_step(stmt);
switch (rc)
{
case SQLITE_DONE:
case SQLITE_OK:
break;
case SQLITE_ROW:
// print results for this row, the only row (hopefully)
//retVal = sqlite3_column_int64(stmt, 0); - primary key values are int64, I think?
retVal = sqlite3_column_int(stmt, 0);
break;
default:
ShowError(rc, "processing", command);
break;
}
} while (rc == SQLITE_ROW);
// finalize the statement to release resources
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK)
ShowError(rc, "finalising", command);
}
if (m_bIsDebugging)
Msg(VarArgs("returning: %i\n", retVal));
return retVal;
}
dbReadResult* dbHandler::ReadMultiple(const char *cmd, ...)
{
va_list marker;
char msg[4096];
va_start(marker, cmd);
Q_vsnprintf(msg, sizeof(msg), cmd, marker);
va_end(marker);
const char *command = VarArgs(msg);
if (m_bIsDebugging)
Msg("%s\n", command);
dbReadResult* output = new dbReadResult();
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, command, -1, &stmt, 0);
if (rc)
{
ShowError(rc, "preparing", command);
}
else
{
int cols = sqlite3_column_count(stmt);
// execute the statement
do
{
rc = sqlite3_step(stmt);
switch (rc)
{
case SQLITE_DONE:
case SQLITE_OK:
break;
case SQLITE_ROW:
for (int col = 0; col<cols; col++)
switch (sqlite3_column_type(stmt, col))
{
case SQLITE_INTEGER:
output->AddToTail(dbValue(sqlite3_column_int(stmt, col))); break;
case SQLITE_TEXT:
output->AddToTail(dbValue((const char*)sqlite3_column_text(stmt, col))); break;
case SQLITE_FLOAT:
output->AddToTail(dbValue(sqlite3_column_double(stmt, col))); break;
case SQLITE_BLOB:
case SQLITE_NULL:
default:
ShowError(rc, "processing", command, "Data type is not supported; must be SQLITE_INTEGER, SQLITE_FLOAT or SQLITE_TEXT!"); break;
}
break;
default:
ShowError(rc, "processing", command);
break;
}
} while (rc == SQLITE_ROW);
// finalize the statement to release resources
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK)
ShowError(rc, "finalising", command);
}
if (m_bIsDebugging)
{
Msg("returning: ");
int num = output->Count();
for (int i = 0; i<num; i++)
{
if (i > 0)
Msg(", ");
switch (output->Element(i).type)
{
case INTEGER:
Msg(VarArgs("%i", output->Element(i).integer)); break;
case TEXT:
Msg(VarArgs("%s", output->Element(i).text)); break;
case FLOATING:
Msg(VarArgs("%f", output->Element(i).floating)); break;
default:
Msg("<INVALID>"); break;
}
}
Msg("\n");
}
return output;
}
int dbHandler::LastInsertID()
{
return sqlite3_last_insert_rowid(db);
}