2016-02-27 10:57:29 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
#include "Common.hpp"
|
2016-07-10 02:00:33 +02:00
|
|
|
#include "Connection.hpp"
|
|
|
|
#include "Statement.hpp"
|
2016-02-27 10:57:29 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-06-03 20:31:00 +02:00
|
|
|
#include <cstdio>
|
2016-04-02 11:11:14 +02:00
|
|
|
#include <cstring>
|
|
|
|
#include <cstdarg>
|
2016-02-27 10:57:29 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-28 15:20:33 +01:00
|
|
|
namespace SqMod {
|
2016-02-27 10:57:29 +01:00
|
|
|
|
2016-07-10 02:00:33 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
Object GetConnectionObj(const ConnRef & conn)
|
|
|
|
{
|
|
|
|
return Object(new Connection(conn));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
Object GetStatementObj(const StmtRef & stmt)
|
|
|
|
{
|
|
|
|
return Object(new Statement(stmt));
|
|
|
|
}
|
|
|
|
|
2016-02-27 10:57:29 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CSStr QFmtStr(CSStr str, ...)
|
|
|
|
{
|
|
|
|
// Initialize the argument list
|
|
|
|
va_list args;
|
|
|
|
va_start (args, str);
|
|
|
|
// Write the requested contents
|
2016-06-03 20:31:00 +02:00
|
|
|
sqlite3_vsnprintf(GetTempBuffSize(), GetTempBuff(), str, args);
|
2016-02-27 10:57:29 +01:00
|
|
|
// Release the argument list
|
|
|
|
va_end(args);
|
|
|
|
// Return the data from the buffer
|
2016-06-03 20:31:00 +02:00
|
|
|
return GetTempBuff();
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool IsQueryEmpty(CSStr str)
|
|
|
|
{
|
|
|
|
// Is the pointer valid?
|
|
|
|
if (!str)
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-02-27 10:57:29 +01:00
|
|
|
return true;
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Currently processed character
|
|
|
|
SQChar c = 0;
|
|
|
|
// See if the query contains any alpha numeric characters
|
|
|
|
while ((c = *str) != 0)
|
|
|
|
{
|
2016-04-02 11:11:14 +02:00
|
|
|
if (std::isalnum(c) != 0)
|
|
|
|
{
|
2016-02-27 10:57:29 +01:00
|
|
|
return false;
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
++str;
|
|
|
|
}
|
|
|
|
// At this point we consider the query empty
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-23 04:43:19 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-27 16:53:12 +01:00
|
|
|
CSStr GetErrStr(Int32 status)
|
|
|
|
{
|
|
|
|
return sqlite3_errstr(status);
|
|
|
|
}
|
|
|
|
|
2016-02-27 10:57:29 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
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
|
2016-02-28 15:20:33 +01:00
|
|
|
const StackGuard sg(_SqVM);
|
2016-02-27 10:57:29 +01:00
|
|
|
// Push a long integer instance with the requested value on the stack
|
2016-07-04 15:26:39 +02:00
|
|
|
SqMod_PushSLongObject(_SqVM, sqlite3_memory_used());
|
2016-02-28 15:20:33 +01:00
|
|
|
// Obtain the object from the stack and return it
|
|
|
|
return Var< Object >(_SqVM, -1).value;
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
Object GetMemoryHighwaterMark(bool reset)
|
|
|
|
{
|
|
|
|
// Obtain the initial stack size
|
2016-02-28 15:20:33 +01:00
|
|
|
const StackGuard sg(_SqVM);
|
2016-02-27 10:57:29 +01:00
|
|
|
// Push a long integer instance with the requested value on the stack
|
2016-07-04 15:26:39 +02:00
|
|
|
SqMod_PushSLongObject(_SqVM, sqlite3_memory_highwater(reset));
|
2016-02-28 15:20:33 +01:00
|
|
|
// Obtain the object from the stack and return it
|
|
|
|
return Var< Object >(_SqVM, -1).value;
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CSStr EscapeString(CSStr str)
|
|
|
|
{
|
|
|
|
// Is there even a string to escape?
|
|
|
|
if (!str)
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-02-27 10:57:29 +01:00
|
|
|
return _SC(""); // Default to empty string
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Attempt to escape the specified string
|
2016-06-03 20:31:00 +02:00
|
|
|
sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), "%q", str);
|
2016-02-27 10:57:29 +01:00
|
|
|
// Return the resulted string
|
2016-06-03 20:31:00 +02:00
|
|
|
return GetTempBuff();
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CCStr EscapeStringEx(SQChar spec, CCStr str)
|
|
|
|
{
|
|
|
|
// Utility that allows changing the format specifier temporarily
|
|
|
|
static SQChar fs[] = _SC("%q");
|
|
|
|
// Validate the specified format specifier
|
2016-04-02 11:11:14 +02:00
|
|
|
if ((spec != 'q') && (spec != 'Q') && (spec != 'w') && (spec != 's'))
|
2016-02-27 10:57:29 +01:00
|
|
|
{
|
2016-04-02 11:11:14 +02:00
|
|
|
STHROWF("Unknown format specifier: '%c'", spec);
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
// Is there even a string to escape?
|
|
|
|
else if (!str)
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-02-27 10:57:29 +01:00
|
|
|
return _SC(""); // Default to empty string
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Apply the format specifier
|
|
|
|
fs[1] = spec;
|
|
|
|
// Attempt to escape the specified string
|
2016-06-03 20:31:00 +02:00
|
|
|
sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), fs, str);
|
2016-02-27 10:57:29 +01:00
|
|
|
// Restore the format specifier
|
2016-02-28 15:20:33 +01:00
|
|
|
fs[1] = 'q';
|
2016-02-27 10:57:29 +01:00
|
|
|
// Return the resulted string
|
2016-06-03 20:31:00 +02:00
|
|
|
return GetTempBuff();
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
CCStr ArrayToQueryColumns(Array & arr)
|
|
|
|
{
|
|
|
|
// Do we even have any elements to process?
|
|
|
|
if (arr.Length() <= 0)
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-02-27 10:57:29 +01:00
|
|
|
return _SC(""); // Default to empty string
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// 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
|
2016-06-03 20:31:00 +02:00
|
|
|
for (; itr != values.end() && offset < GetTempBuffSize(); ++itr)
|
2016-02-27 10:57:29 +01:00
|
|
|
{
|
|
|
|
// Is the name valid?
|
|
|
|
if (itr->empty())
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-03-22 23:25:32 +01:00
|
|
|
STHROWF("Invalid column name");
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Attempt to append the column name to the buffer
|
2016-06-03 20:31:00 +02:00
|
|
|
sqlite3_snprintf(GetTempBuffSize() - offset, GetTempBuff() + offset, "[%q], ", itr->c_str());
|
2016-02-27 10:57:29 +01:00
|
|
|
// 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)
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-06-03 20:31:00 +02:00
|
|
|
GetTempBuff()[offset-2] = '\0';
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
else
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-06-03 20:31:00 +02:00
|
|
|
GetTempBuff()[0] = '\0';
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Return the resulted string
|
2016-06-03 20:31:00 +02:00
|
|
|
return GetTempBuff();
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
2016-02-28 15:20:33 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-27 10:57:29 +01:00
|
|
|
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())
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-03-22 23:25:32 +01:00
|
|
|
STHROWF("Invalid or empty column name");
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Attempt to append the column name to the buffer
|
2016-06-03 20:31:00 +02:00
|
|
|
sqlite3_snprintf(GetTempBuffSize() - offset, GetTempBuff() + offset, "[%q], ", name.c_str());
|
2016-02-27 10:57:29 +01:00
|
|
|
// 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)
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-06-03 20:31:00 +02:00
|
|
|
GetTempBuff()[offset-2] = '\0';
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
else
|
2016-04-02 11:11:14 +02:00
|
|
|
{
|
2016-06-03 20:31:00 +02:00
|
|
|
GetTempBuff()[0] = '\0';
|
2016-04-02 11:11:14 +02:00
|
|
|
}
|
2016-02-27 10:57:29 +01:00
|
|
|
// Return the resulted string
|
2016-06-03 20:31:00 +02:00
|
|
|
return GetTempBuff();
|
2016-02-27 10:57:29 +01:00
|
|
|
}
|
|
|
|
|
2016-06-15 22:49:25 +02:00
|
|
|
// ================================================================================================
|
|
|
|
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("EscapeString"), &EscapeString)
|
|
|
|
.Func(_SC("EscapeStringEx"), &EscapeStringEx)
|
|
|
|
.Func(_SC("Escape"), &EscapeString)
|
|
|
|
.Func(_SC("EscapeEx"), &EscapeStringEx)
|
|
|
|
.Func(_SC("ArrayToQueryColumns"), &ArrayToQueryColumns)
|
|
|
|
.Func(_SC("TableToQueryColumns"), &TableToQueryColumns);
|
|
|
|
}
|
|
|
|
|
2016-02-27 10:57:29 +01:00
|
|
|
} // Namespace:: SqMod
|