mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-09 01:07:16 +01:00
305 lines
9.6 KiB
C++
305 lines
9.6 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Common.hpp"
|
|
#include "Connection.hpp"
|
|
#include "Statement.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <cstdarg>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object GetConnectionObj(const ConnRef & conn)
|
|
{
|
|
return Object(new Connection(conn));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object GetStatementObj(const StmtRef & stmt)
|
|
{
|
|
return Object(new Statement(stmt));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr QFmtStr(CSStr str, ...)
|
|
{
|
|
// Initialize the argument list
|
|
va_list args;
|
|
va_start (args, str);
|
|
// Write the requested contents
|
|
sqlite3_vsnprintf(GetTempBuffSize(), GetTempBuff(), str, args);
|
|
// Release the argument list
|
|
va_end(args);
|
|
// Return the data from the buffer
|
|
return GetTempBuff();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool IsQueryEmpty(CSStr str)
|
|
{
|
|
// Is the pointer valid?
|
|
if (!str)
|
|
{
|
|
return true;
|
|
}
|
|
// Currently processed character
|
|
SQChar c = 0;
|
|
// See if the query contains any alpha numeric characters
|
|
while ((c = *str) != 0)
|
|
{
|
|
if (std::isalnum(c) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
++str;
|
|
}
|
|
// At this point we consider the query empty
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr GetErrStr(Int32 status)
|
|
{
|
|
return sqlite3_errstr(status);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SetSoftHeapLimit(Int32 limit)
|
|
{
|
|
sqlite3_soft_heap_limit(limit);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Int32 ReleaseMemory(Int32 bytes)
|
|
{
|
|
return sqlite3_release_memory(bytes);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object GetMemoryUsage()
|
|
{
|
|
// Obtain the initial stack size
|
|
const StackGuard sg;
|
|
// Push a long integer instance with the requested value on the stack
|
|
SqMod_PushSLongObject(DefaultVM::Get(), sqlite3_memory_used());
|
|
// Obtain the object from the stack and return it
|
|
return Var< Object >(DefaultVM::Get(), -1).value;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object GetMemoryHighwaterMark(bool reset)
|
|
{
|
|
// Obtain the initial stack size
|
|
const StackGuard sg;
|
|
// Push a long integer instance with the requested value on the stack
|
|
SqMod_PushSLongObject(DefaultVM::Get(), sqlite3_memory_highwater(reset));
|
|
// Obtain the object from the stack and return it
|
|
return Var< Object >(DefaultVM::Get(), -1).value;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr EscapeString(CSStr str)
|
|
{
|
|
// Is there even a string to escape?
|
|
if (!str)
|
|
{
|
|
return _SC(""); // Default to empty string
|
|
}
|
|
// Attempt to escape the specified string
|
|
sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), "%q", str);
|
|
// Return the resulted string
|
|
return GetTempBuff();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static SQInteger SqEscapeString(HSQUIRRELVM vm)
|
|
{
|
|
// Was the string specified?
|
|
if (sq_gettop(vm) <= 1)
|
|
{
|
|
return sq_throwerror(vm, "Missing un-escaped string");
|
|
}
|
|
// Attempt to generate the string value
|
|
StackStrF val(vm, 2);
|
|
// Have we failed to retrieve the string?
|
|
if (SQ_FAILED(val.mRes))
|
|
{
|
|
return val.mRes; // Propagate the error!
|
|
}
|
|
// Attempt to escape the obtained string and push it on the stack
|
|
sq_pushstring(vm, EscapeString(val.mPtr), -1);
|
|
// Specify that we have a return value
|
|
return 1;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CCStr EscapeStringEx(SQChar spec, CCStr str)
|
|
{
|
|
// Utility that allows changing the format specifier temporarily
|
|
static SQChar fs[] = _SC("%q");
|
|
// Validate the specified format specifier
|
|
if ((spec != 'q') && (spec != 'Q') && (spec != 'w') && (spec != 's'))
|
|
{
|
|
STHROWF("Unknown format specifier: '%c'", spec);
|
|
}
|
|
// Is there even a string to escape?
|
|
else if (!str)
|
|
{
|
|
return _SC(""); // Default to empty string
|
|
}
|
|
// Apply the format specifier
|
|
fs[1] = spec;
|
|
// Attempt to escape the specified string
|
|
sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), fs, str);
|
|
// Restore the format specifier
|
|
fs[1] = 'q';
|
|
// Return the resulted string
|
|
return GetTempBuff();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static SQInteger SqEscapeStringEx(HSQUIRRELVM vm)
|
|
{
|
|
const Int32 top = sq_gettop(vm);
|
|
// Was the escape specifier specified?
|
|
if (top <= 1)
|
|
{
|
|
return sq_throwerror(vm, "Missing escape specifier");
|
|
}
|
|
// Was the string specified?
|
|
else if (top <= 2)
|
|
{
|
|
return sq_throwerror(vm, "Missing un-escaped string");
|
|
}
|
|
SQInteger spec = 'q';
|
|
// Attempt to extract the escape specifier
|
|
const SQRESULT res = sq_getinteger(vm, 2, &spec);
|
|
// Have we failed to retrieve the specifier?
|
|
if (SQ_FAILED(res))
|
|
{
|
|
return res; // Propagate the error!
|
|
}
|
|
// Attempt to generate the string value
|
|
StackStrF val(vm, 3);
|
|
// Have we failed to retrieve the string?
|
|
if (SQ_FAILED(val.mRes))
|
|
{
|
|
return val.mRes; // Propagate the error!
|
|
}
|
|
// Attempt to escape the obtained string and push it on the stack
|
|
try
|
|
{
|
|
sq_pushstring(vm, EscapeStringEx(static_cast< SQChar >(spec), val.mPtr), -1);
|
|
}
|
|
catch (const Sqrat::Exception & e)
|
|
{
|
|
return sq_throwerror(vm, e.what());
|
|
}
|
|
// Specify that we have a return value
|
|
return 1;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CCStr ArrayToQueryColumns(Array & arr)
|
|
{
|
|
// Do we even have any elements to process?
|
|
if (arr.Length() <= 0)
|
|
{
|
|
return _SC(""); // Default to empty string
|
|
}
|
|
// Allocate a vector with the required amount of column names
|
|
std::vector< String > values(arr.Length());
|
|
// Attempt to extract the array elements as strings
|
|
arr.GetArray< String >(&values[0], values.size());
|
|
// Used to know the position of the next column name
|
|
Uint32 offset = 0;
|
|
// Obtain the start of the array
|
|
std::vector< String >::iterator itr = values.begin();
|
|
// Process all elements within range
|
|
for (; itr != values.end() && offset < GetTempBuffSize(); ++itr)
|
|
{
|
|
// Is the name valid?
|
|
if (itr->empty())
|
|
{
|
|
STHROWF("Invalid column name");
|
|
}
|
|
// Attempt to append the column name to the buffer
|
|
sqlite3_snprintf(GetTempBuffSize() - offset, GetTempBuff() + offset, "[%q], ", itr->c_str());
|
|
// Add the column name size to the offset
|
|
offset += itr->size();
|
|
// Also include the comma and space in the offset
|
|
offset += 2;
|
|
}
|
|
// Trim the last coma and space
|
|
if (offset >= 2)
|
|
{
|
|
GetTempBuff()[offset-2] = '\0';
|
|
}
|
|
else
|
|
{
|
|
GetTempBuff()[0] = '\0';
|
|
}
|
|
// Return the resulted string
|
|
return GetTempBuff();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CCStr TableToQueryColumns(Table & tbl)
|
|
{
|
|
// Used to know the position of the next column name
|
|
Uint32 offset = 0;
|
|
// Used to obtain the column name temporarily
|
|
String name;
|
|
// Obtain the start of the table
|
|
Table::iterator itr;
|
|
// Process all elements within range
|
|
while (tbl.Next(itr))
|
|
{
|
|
// Use the element key as the column name
|
|
name.assign(itr.getName());
|
|
// Is the name valid?
|
|
if (name.empty())
|
|
{
|
|
STHROWF("Invalid or empty column name");
|
|
}
|
|
// Attempt to append the column name to the buffer
|
|
sqlite3_snprintf(GetTempBuffSize() - offset, GetTempBuff() + offset, "[%q], ", name.c_str());
|
|
// Add the column name size to the offset
|
|
offset += name.size();
|
|
// Also include the comma and space in the offset
|
|
offset += 2;
|
|
}
|
|
// Trim the last coma and space
|
|
if (offset >= 2)
|
|
{
|
|
GetTempBuff()[offset-2] = '\0';
|
|
}
|
|
else
|
|
{
|
|
GetTempBuff()[0] = '\0';
|
|
}
|
|
// Return the resulted string
|
|
return GetTempBuff();
|
|
}
|
|
|
|
// ================================================================================================
|
|
void Register_Common(Table & sqlns)
|
|
{
|
|
sqlns.Func(_SC("IsQueryEmpty"), &IsQueryEmpty)
|
|
.Func(_SC("GetErrStr"), &GetErrStr)
|
|
.Func(_SC("SetSoftHeapLimit"), &SetSoftHeapLimit)
|
|
.Func(_SC("ReleaseMemory"), &ReleaseMemory)
|
|
.Func(_SC("MemoryUsage"), &GetMemoryUsage)
|
|
.Func(_SC("ArrayToQueryColumns"), &ArrayToQueryColumns)
|
|
.Func(_SC("TableToQueryColumns"), &TableToQueryColumns)
|
|
.SquirrelFunc(_SC("EscapeString"), &SqEscapeString)
|
|
.SquirrelFunc(_SC("EscapeStringEx"), &SqEscapeStringEx)
|
|
.SquirrelFunc(_SC("Escape"), &SqEscapeString)
|
|
.SquirrelFunc(_SC("EscapeEx"), &SqEscapeStringEx);
|
|
}
|
|
|
|
} // Namespace:: SqMod
|