// ------------------------------------------------------------------------------------------------ #include "Field.hpp" // ------------------------------------------------------------------------------------------------ #include #include #include // ------------------------------------------------------------------------------------------------ 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) 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) 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 const StackStrF val(vm, -1, false); // Validate the result if (SQ_FAILED(val.mRes)) { 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 const StackStrF val(vm, -1, false); // Validate the result if (SQ_FAILED(val.mRes)) { 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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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_CREATED(*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 and return it return Var< Object >(DefaultVM::Get(), -1).value; } // ------------------------------------------------------------------------------------------------ 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