tinymux/mux/modules/engine/sqlite_backend.cpp
Stephen Dennis 7abc78e781 fix(lua/jit,tests): tonumber CALL_VAL; tests/db LBUF_SIZE (#1866 #1868)
tonumber can return int or float; claiming TY_INT always used CALL_INT and
post-entry declined on float results.  Drop it from the int-return claim
so CALL_VAL preserves the typed stack value.  EXEC pins "3.5"/"3.0"/"17".

Standalone tests/db never saw LBUF_SIZE (no alloc.h).  Define it in the
Makefile to match alloc.h, and include <cstring> in sqlite_backend for
the same TINYMUX_TYPES_DEFINED compile path.
2026-07-31 09:06:07 -06:00

162 lines
4 KiB
C++

/*! \file sqlite_backend.cpp
* \brief SQLite implementation of IStorageBackend.
*
*/
#if !defined(TINYMUX_TYPES_DEFINED)
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"
#endif
#include "sqlite_backend.h"
#include <cstring>
CSQLiteBackend::CSQLiteBackend()
{
}
CSQLiteBackend::~CSQLiteBackend()
{
Close();
}
bool CSQLiteBackend::Open(const char *path)
{
return m_db.Open(path);
}
void CSQLiteBackend::Close()
{
m_db.Close();
}
bool CSQLiteBackend::IsOpen() const
{
return m_db.IsOpen();
}
bool CSQLiteBackend::Get(unsigned int object, unsigned int attrnum,
UTF8 *buf, size_t buflen, size_t *pLen,
int *owner, int *flags)
{
dbref db_owner;
int db_flags;
bool rc = m_db.GetAttribute(static_cast<dbref>(object), static_cast<int>(attrnum),
buf, buflen, pLen, &db_owner, &db_flags);
if (rc)
{
if (owner) *owner = static_cast<int>(db_owner);
if (flags) *flags = db_flags;
}
return rc;
}
bool CSQLiteBackend::Put(unsigned int object, unsigned int attrnum,
const UTF8 *value, size_t len,
int owner, int flags)
{
return m_db.PutAttribute(static_cast<dbref>(object), static_cast<int>(attrnum),
value, len, static_cast<dbref>(owner), flags);
}
bool CSQLiteBackend::Del(unsigned int object, unsigned int attrnum)
{
return m_db.DelAttribute(static_cast<dbref>(object), static_cast<int>(attrnum));
}
bool CSQLiteBackend::DelAll(unsigned int object)
{
return m_db.DelAllAttributes(static_cast<dbref>(object));
}
bool CSQLiteBackend::GetAll(unsigned int object, AttrCallback cb)
{
return m_db.GetAllAttributes(static_cast<dbref>(object),
[&cb](int attrnum, const UTF8 *value, size_t len, dbref owner, int flags)
{
cb(static_cast<unsigned int>(attrnum), value, len,
static_cast<int>(owner), flags);
});
}
bool CSQLiteBackend::GetBuiltin(unsigned int object, AttrCallback cb)
{
return m_db.GetBuiltinAttributes(static_cast<dbref>(object),
[&cb](int attrnum, const UTF8 *value, size_t len, dbref owner, int flags)
{
cb(static_cast<unsigned int>(attrnum), value, len,
static_cast<int>(owner), flags);
});
}
int CSQLiteBackend::Count(unsigned int object)
{
return m_db.CountAttributes(static_cast<dbref>(object));
}
uint32_t CSQLiteBackend::GetModCount(unsigned int object, unsigned int attrnum)
{
return m_db.GetAttrModCount(static_cast<dbref>(object),
static_cast<int>(attrnum));
}
bool CSQLiteBackend::GetAllModCounts(unsigned int object, ModCountCallback cb)
{
m_db.GetAllAttrModCounts(static_cast<dbref>(object),
[&cb](int attrnum, uint32_t mc)
{
cb(static_cast<unsigned int>(attrnum), mc);
});
return true;
}
void CSQLiteBackend::Sync()
{
m_db.Checkpoint();
}
void CSQLiteBackend::Tick()
{
// Write-through means SQLite is always up to date.
// Periodic optimize is light maintenance.
//
m_db.Optimize();
}
bool derive_sqlite_path(char *buf, size_t buflen, const UTF8 *indb)
{
if ( nullptr == buf
|| 0 == buflen
|| nullptr == indb)
{
return false;
}
static const char suffix[] = ".sqlite";
const size_t nSuffix = sizeof(suffix) - 1;
const char *pIn = reinterpret_cast<const char *>(indb);
size_t nIn = strlen(pIn);
// A trailing ".db" is replaced rather than appended to, so the base is
// shorter than the input in that case. Note this still grows the path:
// three characters out, seven in.
//
size_t nBase = nIn;
if ( 3 < nIn
&& 0 == strcmp(pIn + nIn - 3, ".db"))
{
nBase = nIn - 3;
}
if (buflen < nBase + nSuffix + 1)
{
return false;
}
memcpy(buf, pIn, nBase);
memcpy(buf + nBase, suffix, nSuffix + 1);
return true;
}