1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 16:57:16 +01:00
SqMod/modules/mysql/Connection.cpp

420 lines
13 KiB
C++
Raw Normal View History

// ------------------------------------------------------------------------------------------------
#include "Connection.hpp"
#include "Account.hpp"
#include "Statement.hpp"
#include "ResultSet.hpp"
#include "Transaction.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstring>
#include <vector>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQInteger Connection::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqMySQLConnection");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Connection::Validate(CCStr file, Int32 line) const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL connection reference =>[%s:%d]", file, line);
}
}
#else
void Connection::Validate() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL connection reference");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Connection::ValidateCreated(CCStr file, Int32 line) const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL connection reference =>[%s:%d]", file, line);
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL connection =>[%s:%d]", file, line);
}
}
#else
void Connection::ValidateCreated() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL connection reference");
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL connection");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & Connection::GetValid(CCStr file, Int32 line) const
{
Validate(file, line);
return m_Handle;
}
#else
const ConnRef & Connection::GetValid() const
{
Validate();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & Connection::GetCreated(CCStr file, Int32 line) const
{
ValidateCreated(file, line);
return m_Handle;
}
#else
const ConnRef & Connection::GetCreated() const
{
ValidateCreated();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
Object Connection::Insert(CSStr query)
{
// Make sure the specified query is valid
if (!query || *query == '\0')
{
STHROWF("Invalid or empty MySQL query");
}
// Attempt to execute the specified query
else if (mysql_real_query(SQMOD_GET_CREATED(*this)->mPtr, query, std::strlen(query)) != 0)
{
SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query");
}
// Return the identifier of the inserted row
return MakeULongObj(mysql_insert_id(m_Handle->mPtr));
}
// ------------------------------------------------------------------------------------------------
ResultSet Connection::Query(CSStr query)
{
// Make sure the specified query is valid
if (!query || *query == '\0')
{
STHROWF("Invalid or empty MySQL query");
}
// Attempt to execute the specified query
else if (mysql_real_query(SQMOD_GET_CREATED(*this)->mPtr, query, std::strlen(query)) != 0)
{
SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query");
}
// Return the identifier of the inserted row
return ResultSet(m_Handle);
}
// ------------------------------------------------------------------------------------------------
Statement Connection::GetStatement(CSStr query)
{
return Statement(SQMOD_GET_CREATED(*this), query);
}
// ------------------------------------------------------------------------------------------------
Transaction Connection::GetTransaction()
{
return Transaction();
}
// ------------------------------------------------------------------------------------------------
SQInteger Connection::ExecuteF(HSQUIRRELVM vm)
{
const Int32 top = sq_gettop(vm);
// Was the query value specified?
if (top <= 1)
{
return sq_throwerror(vm, "Missing query value");
}
// The connection instance
Connection * conn = nullptr;
// Attempt to extract the argument values
try
{
conn = Var< Connection * >(vm, 1).value;
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Do we have a valid connection instance?
if (!conn)
{
return sq_throwerror(vm, "Invalid MySQL connection instance");
}
// Validate the connection info
try
{
SQMOD_VALIDATE_CREATED(*conn);
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Attempt to retrieve the value from the stack as a string
StackStrF val(vm, 2, true);
// Have we failed to retrieve the string?
if (SQ_FAILED(val.mRes))
{
return val.mRes; // Propagate the error!
}
// Make sure the query string is valid
else if (!(val.mPtr) || *(val.mPtr) == '\0')
{
STHROWF("Invalid or empty MySQL query");
}
// Attempt to execute the specified query
try
{
const SQRESULT res = SqMod_PushULongObject(vm, conn->m_Handle->Execute(val.mPtr, val.mLen));
// Validate the result of pushing the number of database changes on the stack
if (SQ_FAILED(res))
{
return res; // Propagate the error!
}
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// This function returned a value
return 1;
}
// ------------------------------------------------------------------------------------------------
SQInteger Connection::InsertF(HSQUIRRELVM vm)
{
const Int32 top = sq_gettop(vm);
// Was the query value specified?
if (top <= 1)
{
return sq_throwerror(vm, "Missing query value");
}
// The connection instance
Connection * conn = nullptr;
// Attempt to extract the argument values
try
{
conn = Var< Connection * >(vm, 1).value;
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Do we have a valid connection instance?
if (!conn)
{
return sq_throwerror(vm, "Invalid MySQL connection instance");
}
// Validate the connection info
try
{
SQMOD_VALIDATE_CREATED(*conn);
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Attempt to retrieve the value from the stack as a string
StackStrF val(vm, 2, true);
// Have we failed to retrieve the string?
if (SQ_FAILED(val.mRes))
{
return val.mRes; // Propagate the error!
}
// Make sure the query string is valid
else if (!(val.mPtr) || *(val.mPtr) == '\0')
{
return sq_throwerror(vm, "Invalid or empty MySQL query");
}
// Attempt to execute the specified query
try
{
if (mysql_real_query(conn->m_Handle->mPtr, val.mPtr, val.mLen) != 0)
{
SQMOD_THROW_CURRENT(*(conn->m_Handle), "Unable to execute MySQL query");
}
// Return the identifier of the inserted row
const SQRESULT res = SqMod_PushULongObject(vm, mysql_insert_id(conn->m_Handle->mPtr));
// Validate the result of pushing the identifier of the inserted row
if (SQ_FAILED(res))
{
return res; // Propagate the error!
}
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// This function returned a value
return 1;
}
// ------------------------------------------------------------------------------------------------
SQInteger Connection::QueryF(HSQUIRRELVM vm)
{
const Int32 top = sq_gettop(vm);
// Was the query value specified?
if (top <= 1)
{
return sq_throwerror(vm, "Missing query value");
}
// The connection instance
Connection * conn = nullptr;
// Attempt to extract the argument values
try
{
conn = Var< Connection * >(vm, 1).value;
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Do we have a valid connection instance?
if (!conn)
{
return sq_throwerror(vm, "Invalid MySQL connection instance");
}
// Validate the connection info
try
{
SQMOD_VALIDATE_CREATED(*conn);
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// Attempt to retrieve the value from the stack as a string
StackStrF val(vm, 2, true);
// Have we failed to retrieve the string?
if (SQ_FAILED(val.mRes))
{
return val.mRes; // Propagate the error!
}
// Make sure the query string is valid
else if (!(val.mPtr) || *(val.mPtr) == '\0')
{
return sq_throwerror(vm, "Invalid or empty MySQL query");
}
// Attempt to execute the specified query
try
{
if (mysql_real_query(conn->m_Handle->mPtr, val.mPtr, val.mLen) != 0)
{
SQMOD_THROW_CURRENT(*(conn->m_Handle), "Unable to execute MySQL query");
}
// Return a new instance with the obtained result set
Var< ResultSet * >::push(vm, new ResultSet(conn->m_Handle));
}
catch (const Sqrat::Exception & e)
{
// Propagate the error
return sq_throwerror(vm, e.what());
}
// This function returned a value
return 1;
}
// ------------------------------------------------------------------------------------------------
LightObj Connection::EscapeString(const StackStrF & str)
{
// Is there even a string to escape?
if (str.mLen <= 0)
{
return LightObj(_SC(""), 0, str.mVM); // Default to empty string
}
// Allocate a buffer for the given string
std::vector< SQChar > buffer(str.mLen * 2 + 1);
// Attempt to ecape the specified string
const Ulong len = mysql_real_escape_string(m_Handle->mPtr, buffer.data(), str.mPtr, str.mLen);
// Return the resulted string
return LightObj(buffer.data(), static_cast< SQInteger >(len), str.mVM);
}
// ================================================================================================
void Register_Connection(Table & sqlns)
{
sqlns.Bind(_SC("Connection")
, Class< Connection >(sqlns.GetVM(), _SC("SqMySQLConnection"))
// Constructors
.Ctor()
.Ctor< const Account & >()
// Core Meta-methods
.Func(_SC("_cmp"), &Connection::Cmp)
.SquirrelFunc(_SC("_typename"), &Connection::Typename)
.Func(_SC("_tostring"), &Connection::ToString)
// Properties
.Prop(_SC("IsValid"), &Connection::IsValid)
.Prop(_SC("Connected"), &Connection::IsConnected)
.Prop(_SC("References"), &Connection::GetRefCount)
.Prop(_SC("ErrNo"), &Connection::GetErrNo)
.Prop(_SC("ErrStr"), &Connection::GetErrStr)
.Prop(_SC("LastErrNo"), &Connection::GetLastErrNo)
.Prop(_SC("LastErrStr"), &Connection::GetLastErrStr)
.Prop(_SC("Port"), &Connection::GetPortNum)
.Prop(_SC("Host"), &Connection::GetHost)
.Prop(_SC("User"), &Connection::GetUser)
.Prop(_SC("Pass"), &Connection::GetPass)
.Prop(_SC("Name"), &Connection::GetName, &Connection::SetName)
.Prop(_SC("Socket"), &Connection::GetSocket)
.Prop(_SC("Flags"), &Connection::GetFlags)
.Prop(_SC("SSL_Key"), &Connection::GetSSL_Key)
.Prop(_SC("SSL_Cert"), &Connection::GetSSL_Cert)
.Prop(_SC("SSL_CA"), &Connection::GetSSL_CA)
.Prop(_SC("SSL_CA_Path"), &Connection::GetSSL_CA_Path)
.Prop(_SC("SSL_Cipher"), &Connection::GetSSL_Cipher)
.Prop(_SC("Charset"), &Connection::GetCharset, &Connection::SetCharset)
.Prop(_SC("AutoCommit"), &Connection::GetAutoCommit, &Connection::SetAutoCommit)
.Prop(_SC("InTransaction"), &Connection::GetInTransaction)
// Member Methods
.Func(_SC("Disconnect"), &Connection::Disconnect)
.Func(_SC("SelectDb"), &Connection::SetName)
.Func(_SC("Execute"), &Connection::Execute)
.Func(_SC("Insert"), &Connection::Insert)
.Func(_SC("Query"), &Connection::Query)
.Func(_SC("Statement"), &Connection::GetStatement)
.Func(_SC("Transaction"), &Connection::GetTransaction)
.FmtFunc(_SC("EscapeString"), &Connection::EscapeString)
// Squirrel Methods
.SquirrelFunc(_SC("ExecuteF"), &Connection::ExecuteF)
.SquirrelFunc(_SC("InsertF"), &Connection::InsertF)
.SquirrelFunc(_SC("QueryF"), &Connection::QueryF)
);
}
} // Namespace:: SqMod