1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-14 03:37:16 +01:00
SqMod/modules/mysql/Field.cpp

588 lines
20 KiB
C++
Raw Normal View History

// ------------------------------------------------------------------------------------------------
#include "Field.hpp"
// ------------------------------------------------------------------------------------------------
#include <cerrno>
#include <cstdlib>
#include <cstring>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
static inline bool IsDigitsOnly(CSStr str)
{
while (std::isdigit(*str) || std::isspace(*str))
{
++str;
}
// Return whether we reached the end while searching
return *str == '\0';
}
// ------------------------------------------------------------------------------------------------
const Uint32 Field::INVALID_INDEX = std::numeric_limits< Uint32 >::max();
// ------------------------------------------------------------------------------------------------
SQInteger Field::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqMySQLField");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Field::Validate(CCStr file, Int32 line) const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
// Are we pointing to a valid index?
else if (m_Index >= m_Handle->mFieldCount)
{
SqThrowF("Field index is out of range: %u >= %lu =>[%s:%d]",
m_Index, m_Handle->mFieldCount, file, line);
}
}
#else
void Field::Validate() const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference");
}
// Are we pointing to a valid index?
else if (m_Index >= m_Handle->mFieldCount)
{
SqThrowF("Field index is out of range: %u >= %lu", m_Index, m_Handle->mFieldCount);
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Field::ValidateCreated(CCStr file, Int32 line) const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
// Are we pointing to a valid index?
m_Handle->ValidateField(m_Index, file, line);
}
#else
void Field::ValidateCreated() const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference");
}
// Are we pointing to a valid index?
m_Handle->ValidateField(m_Index);
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Field::ValidateStepped(CCStr file, Int32 line) const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
// Do we have a valid row available?
else if (m_Handle->mRow == nullptr)
{
SqThrowF("No row available in MySQL result-set =>[%s:%d]", file, line);
}
// Are we pointing to a valid index?
m_Handle->ValidateField(m_Index, file, line);
}
#else
void Field::ValidateStepped() const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference");
}
// Do we have a valid row available?
else if (m_Handle->mRow == nullptr)
{
SqThrowF("No row available in MySQL result-set");
}
// Are we pointing to a valid index?
m_Handle->ValidateField(m_Index);
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & Field::GetValid(CCStr file, Int32 line) const
{
Validate(file, line);
return m_Handle;
}
#else
const ResRef & Field::GetValid() const
{
Validate();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & Field::GetCreated(CCStr file, Int32 line) const
{
ValidateCreated(file, line);
return m_Handle;
}
#else
const ResRef & Field::GetCreated() const
{
ValidateCreated();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & Field::GetStepped(CCStr file, Int32 line) const
{
ValidateStepped(file, line);
return m_Handle;
}
#else
const ResRef & Field::GetStepped() const
{
ValidateStepped();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Field::ValidateField(Uint32 idx, CCStr file, Int32 line) const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
// Validate the specified field index
m_Handle->ValidateField(idx, file, line);
}
#else
void Field::ValidateField(Uint32 idx) const
{
// Do we have a valid result-set handle?
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference");
}
// Validate the specified field index
m_Handle->ValidateField(idx);
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
void Field::SetIndex(const Object & field)
{
// Where the index will be extracted
Uint32 idx = INVALID_INDEX;
// Grab the object virtual machine
HSQUIRRELVM vm = field.GetVM();
// Remember the current stack size
const StackGuard sg(vm);
// Push the specified object onto the stack
Var< const Object & >::push(vm, field);
// Identify the type of field was given
switch (field.GetType())
{
// Is this a string value?
case OT_STRING:
{
// Obtain the object from the stack as a string
StackStrF val(vm, -1);
// Validate the result
if (SQ_FAILED(val.Proc(false)))
{
STHROWF("%s", LastErrorString(vm).c_str());
}
// Is the obtained string empty?
else if (val.mLen <= 0)
{
STHROWF("Cannot use an empty field name");
}
// Attempt to find a field with the specified name
idx = m_Handle->GetFieldIndex(val.mPtr);
} break;
// Is this an integer value? (or at least can be easily converted to one)
case OT_INTEGER:
case OT_FLOAT:
case OT_BOOL:
{
idx = ConvTo< Uint32 >::From(SqMod_PopStackInteger(vm, -1));
} break;
// Is this an instance that we can extract either a string or integer from it?
case OT_INSTANCE:
{
// Obtain the object from the stack as a string
StackStrF val(vm, -1);
// Validate the result
if (SQ_FAILED(val.Proc(false)))
{
STHROWF("%s", LastErrorString(vm).c_str());
}
// Is the obtained string empty?
else if (val.mLen <= 0)
{
STHROWF("Cannot use an empty field name");
}
// Check if this value is made only of digits
else if (IsDigitsOnly(val.mPtr))
{
idx = ConvNum< Uint32 >::FromStr(val.mPtr);
}
// Attempt to find a field with the specified name
else
{
idx = m_Handle->GetFieldIndex(val.mPtr);
}
} break;
// We don't recognize this kind of value!
default: STHROWF("Unknown field index of type (%s)", SqTypeName(field.GetType()));
}
// Validate the obtained field index
SQMOD_VALIDATE_FIELD(*this, idx);
// Assign the new index
m_Index = idx;
}
// ------------------------------------------------------------------------------------------------
Object Field::GetResultSet() const
{
return Object();
}
// ------------------------------------------------------------------------------------------------
Object Field::GetConnection() const
{
return Object();
}
// ------------------------------------------------------------------------------------------------
bool Field::GetBoolean() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< bool >::From(m_Handle->mBinds[m_Index].mUint64);
}
// Retrieve the value directly from the row
return DbConvTo< bool >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQChar Field::GetChar() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< SQChar >::From(m_Handle->mBinds[m_Index].mInt32[0]);
}
// Retrieve the value directly from the row
return DbConvTo< SQChar >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetInteger() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
#ifdef _SQ64
return ConvTo< SQInteger >::From(m_Handle->mBinds[m_Index].mInt64);
#else
return ConvTo< SQInteger >::From(m_Handle->mBinds[m_Index].mInt32[0]);
#endif // _SQ64
}
// Retrieve the value directly from the row
return DbConvTo< SQInteger >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQFloat Field::GetFloat() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
#ifdef SQUSEDOUBLE
return ConvTo< SQFloat >::From(m_Handle->mBinds[m_Index].mFloat64);
#else
return ConvTo< SQFloat >::From(m_Handle->mBinds[m_Index].mFloat32[0]);
#endif // SQUSEDOUBLE
}
// Retrieve the value directly from the row
return DbConvTo< SQFloat >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetInt8() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Int8 >::From(m_Handle->mBinds[m_Index].mInt64);
}
// Retrieve the value directly from the row
return DbConvTo< Int8 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetUint8() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Uint8 >::From(m_Handle->mBinds[m_Index].mInt64);
}
// Retrieve the value directly from the row
return DbConvTo< Uint8 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetInt16() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Int16 >::From(m_Handle->mBinds[m_Index].mInt64);
}
// Retrieve the value directly from the row
return DbConvTo< Int16 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetUint16() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Uint16 >::From(m_Handle->mBinds[m_Index].mInt64);
}
// Retrieve the value directly from the row
return DbConvTo< Uint16 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetInt32() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Int32 >::From(m_Handle->mBinds[m_Index].mInt64);
}
// Retrieve the value directly from the row
return DbConvTo< Int32 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQInteger Field::GetUint32() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Uint32 >::From(m_Handle->mBinds[m_Index].mInt64);
}
// Retrieve the value directly from the row
return DbConvTo< Uint32 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
Object Field::GetInt64() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Obtain the initial stack size
const StackGuard sg;
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
SqMod_PushSLongObject(DefaultVM::Get(),
ConvTo< Int64 >::From(m_Handle->mBinds[m_Index].mInt64));
}
// Retrieve the value directly from the row
else
{
SqMod_PushSLongObject(DefaultVM::Get(),
DbConvTo< Int64 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type));
}
// Obtain the object from the stack and return it
return Var< Object >(DefaultVM::Get(), -1).value;
}
// ------------------------------------------------------------------------------------------------
Object Field::GetUint64() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Obtain the initial stack size
const StackGuard sg;
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
SqMod_PushULongObject(DefaultVM::Get(),
ConvTo< Uint64 >::From(m_Handle->mBinds[m_Index].mUint64));
}
// Retrieve the value directly from the row
else
{
SqMod_PushULongObject(DefaultVM::Get(),
DbConvTo< Uint64 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type));
}
// Obtain the object from the stack and return it
return Var< Object >(DefaultVM::Get(), -1).value;
}
// ------------------------------------------------------------------------------------------------
SQFloat Field::GetFloat32() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Float32 >::From(m_Handle->mBinds[m_Index].mFloat32[0]);
}
// Retrieve the value directly from the row
return DbConvTo< Float32 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
SQFloat Field::GetFloat64() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement)
{
return ConvTo< Float64 >::From(m_Handle->mBinds[m_Index].mFloat64);
}
// Retrieve the value directly from the row
return DbConvTo< Float64 >::From(m_Handle->mRow[m_Index],
m_Handle->mLengths[m_Index],
m_Handle->mFields[m_Index].type);
}
// ------------------------------------------------------------------------------------------------
Object Field::GetString() const
{
SQMOD_VALIDATE_STEPPED(*this);
// Obtain the initial stack size
const StackGuard sg;
// Retrieve the value directly from the row and push it on the stack
sq_pushstring(DefaultVM::Get(), m_Handle->mRow[m_Index], m_Handle->mLengths[m_Index]);
// Obtain the object from the stack
Object stro(-1, DefaultVM::Get());
// Restore the stack
sg.Restore();
// Return it the string object
return stro;
}
// ------------------------------------------------------------------------------------------------
Object Field::GetBuffer() const
{
return NullObject();
}
// ------------------------------------------------------------------------------------------------
Object Field::GetBlob() const
{
return NullObject();
}
// ================================================================================================
void Register_Field(Table & sqlns)
{
sqlns.Bind(_SC("Field"),
Class< Field >(sqlns.GetVM(), _SC("SqMySQLField"))
// Constructors
.Ctor()
.Ctor< const Field & >()
// Meta-methods
.Func(_SC("_cmp"), &Field::Cmp)
.SquirrelFunc(_SC("_typename"), &Field::Typename)
.Func(_SC("_tostring"), &Field::ToString)
// Properties
.Prop(_SC("IsValid"), &Field::IsValid)
.Prop(_SC("References"), &Field::GetRefCount)
.Prop(_SC("Index"), &Field::GetIndex)
.Prop(_SC("ResultSet"), &Field::GetResultSet)
.Prop(_SC("Connection"), &Field::GetConnection)
.Prop(_SC("Bool"), &Field::GetBoolean)
.Prop(_SC("Boolean"), &Field::GetBoolean)
.Prop(_SC("Char"), &Field::GetChar)
.Prop(_SC("Integer"), &Field::GetInteger)
.Prop(_SC("Float"), &Field::GetFloat)
.Prop(_SC("Int8"), &Field::GetInt8)
.Prop(_SC("Uint8"), &Field::GetUint8)
.Prop(_SC("Int16"), &Field::GetInt16)
.Prop(_SC("Uint16"), &Field::GetUint16)
.Prop(_SC("Int32"), &Field::GetInt32)
.Prop(_SC("Uint32"), &Field::GetUint32)
.Prop(_SC("Int64"), &Field::GetInt64)
.Prop(_SC("Uint64"), &Field::GetUint64)
.Prop(_SC("Float32"), &Field::GetFloat32)
.Prop(_SC("Float64"), &Field::GetFloat64)
.Prop(_SC("String"), &Field::GetString)
.Prop(_SC("Buffer"), &Field::GetBuffer)
.Prop(_SC("Blob"), &Field::GetBlob)
// Member Methods
.Func(_SC("Release"), &Field::Release)
);
}
} // Namespace:: SqMod