ds@1952: /**
ds@1952: * vim: set ts=4 :
ds@1952: * =============================================================================
ds@1952: * SourceMod
ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1952: * =============================================================================
ds@1952: *
ds@1952: * This program is free software; you can redistribute it and/or modify it under
ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952: * Free Software Foundation.
ds@1952: *
ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1952: * details.
ds@1952: *
ds@1952: * You should have received a copy of the GNU General Public License along with
ds@1952: * this program. If not, see .
ds@1952: *
ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1952: * this exception to all derivative works. AlliedModders LLC defines further
ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952: * or .
ds@1952: *
ds@1952: * Version: $Id$
ds@1952: */
ds@1952:
ds@1952: #include "sm_globals.h"
ds@1952: #include "HandleSys.h"
ds@1952: #include "Database.h"
ds@1952: #include "ExtensionSys.h"
ds@1952: #include "PluginSys.h"
ds@1952: #include "sm_stringutil.h"
ds@1952:
ds@1952: HandleType_t hQueryType;
ds@1952: HandleType_t hStmtType;
ds@1952:
ds@1952: class DatabaseHelpers :
ds@1952: public SMGlobalClass,
ds@1952: public IHandleTypeDispatch
ds@1952: {
ds@1952: public:
ds@1952: virtual void OnSourceModAllInitialized()
ds@1952: {
ds@1952: HandleAccess acc;
ds@1952:
ds@1952: /* Disable cloning */
ds@1952: g_HandleSys.InitAccessDefaults(NULL, &acc);
ds@1952: acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
ds@1952:
ds@1952: TypeAccess tacc;
ds@1952:
ds@1952: g_HandleSys.InitAccessDefaults(&tacc, NULL);
ds@1952: tacc.ident = g_pCoreIdent;
ds@1952:
ds@1952: hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
ds@1952: hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, g_pCoreIdent, NULL);
ds@1952: }
ds@1952:
ds@1952: virtual void OnSourceModShutdown()
ds@1952: {
ds@1952: g_HandleSys.RemoveType(hStmtType, g_pCoreIdent);
ds@1952: g_HandleSys.RemoveType(hQueryType, g_pCoreIdent);
ds@1952: }
ds@1952:
ds@1952: virtual void OnHandleDestroy(HandleType_t type, void *object)
ds@1952: {
ds@1952: if (type == hQueryType)
ds@1952: {
ds@1952: IQuery *query = (IQuery *)object;
ds@1952: query->Destroy();
ds@1952: } else if (type == hStmtType) {
ds@1952: IPreparedQuery *query = (IPreparedQuery *)object;
ds@1952: query->Destroy();
ds@1952: }
ds@1952: }
ds@1952: } s_DatabaseNativeHelpers;
ds@1952:
ds@1952: //is this safe for stmt handles? i think since it's single inheritance, it always will be.
ds@1952: inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
ds@1952: {
ds@1952: HandleSecurity sec;
ds@1952: sec.pOwner = pContext->GetIdentity();
ds@1952: sec.pIdentity = g_pCoreIdent;
ds@1952:
ds@1952: return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query);
ds@1952: }
ds@1952:
ds@1952: inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
ds@1952: {
ds@1952: HandleSecurity sec;
ds@1952: sec.pOwner = pContext->GetIdentity();
ds@1952: sec.pIdentity = g_pCoreIdent;
ds@1952:
ds@1952: return g_HandleSys.ReadHandle(hndl, hStmtType, &sec, (void **)query);
ds@1952: }
ds@1952:
ds@1952: inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
ds@1952: {
ds@1952: HandleError err;
ds@1952: if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
ds@1952: {
ds@1952: *db = NULL;
ds@1952: return ReadStmtHndl(hndl, pContext, query);
ds@1952: }
ds@1952: return err;
ds@1952: }
ds@1952:
ds@1952: class TQueryOp : public IDBThreadOperation
ds@1952: {
ds@1952: public:
ds@1952: TQueryOp(IDatabase *db, IPluginFunction *pf, const char *query, cell_t data) :
ds@1952: m_pDatabase(db), m_pFunction(pf), m_Query(query), m_Data(data),
ds@1952: me(g_PluginSys.GetPluginByCtx(pf->GetParentContext()->GetContext())),
ds@1952: m_pQuery(NULL)
ds@1952: {
ds@1952: /* We always increase the reference count because this is potentially
ds@1952: * asynchronous. Otherwise the original handle could be closed while
ds@1952: * we're still latched onto it.
ds@1952: */
ds@1952: m_pDatabase->IncReferenceCount();
ds@1952:
ds@1952: /* Now create our own Handle such that it can only be closed by us.
ds@1952: * We allow cloning just in case someone wants to hold onto it.
ds@1952: */
ds@1952: HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
ds@1952: HandleAccess access;
ds@1952: g_HandleSys.InitAccessDefaults(NULL, &access);
ds@1952: access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
ds@1952: m_MyHandle = g_HandleSys.CreateHandleEx(g_DBMan.GetDatabaseType(),
ds@1952: db,
ds@1952: &sec,
ds@1952: &access,
ds@1952: NULL);
ds@1952: }
ds@1952: ~TQueryOp()
ds@1952: {
ds@1952: if (m_pQuery)
ds@1952: {
ds@1952: m_pQuery->Destroy();
ds@1952: }
ds@1952:
ds@1952: /* Close our Handle if it's valid. */
ds@1952: if (m_MyHandle != BAD_HANDLE)
ds@1952: {
ds@1952: HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
ds@1952: g_HandleSys.FreeHandle(m_MyHandle, &sec);
ds@1952: } else {
ds@1952: /* Otherwise, there is an open ref to the db */
ds@1952: m_pDatabase->Close();
ds@1952: }
ds@1952: }
ds@1952: IdentityToken_t *GetOwner()
ds@1952: {
ds@1952: return me->GetIdentity();
ds@1952: }
ds@1952: IDBDriver *GetDriver()
ds@1952: {
ds@1952: return m_pDatabase->GetDriver();
ds@1952: }
ds@1952: void RunThreadPart()
ds@1952: {
ds@1952: m_pDatabase->LockForFullAtomicOperation();
ds@1952: m_pQuery = m_pDatabase->DoQuery(m_Query.c_str());
ds@1952: if (!m_pQuery)
ds@1952: {
ds@1952: UTIL_Format(error, sizeof(error), "%s", m_pDatabase->GetError());
ds@1952: }
ds@1952: m_pDatabase->UnlockFromFullAtomicOperation();
ds@1952: }
ds@1952: void CancelThinkPart()
ds@1952: {
ds@1952: m_pFunction->PushCell(BAD_HANDLE);
ds@1952: m_pFunction->PushCell(BAD_HANDLE);
ds@1952: m_pFunction->PushString("Driver is unloading");
ds@1952: m_pFunction->PushCell(m_Data);
ds@1952: m_pFunction->Execute(NULL);
ds@1952: }
ds@1952: void RunThinkPart()
ds@1952: {
ds@1952: /* Create a Handle for our query */
ds@1952: HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
ds@1952: HandleAccess access;
ds@1952: g_HandleSys.InitAccessDefaults(NULL, &access);
ds@1952: access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
ds@1952:
ds@1952: Handle_t qh = BAD_HANDLE;
ds@1952:
ds@1952: if (m_pQuery)
ds@1952: {
ds@1952: qh = g_HandleSys.CreateHandle(hQueryType, m_pQuery, me->GetIdentity(), g_pCoreIdent, NULL);
ds@1952: if (qh != BAD_HANDLE)
ds@1952: {
ds@1952: m_pQuery = NULL;
ds@1952: } else {
ds@1952: UTIL_Format(error, sizeof(error), "Could not alloc handle");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: m_pFunction->PushCell(m_MyHandle);
ds@1952: m_pFunction->PushCell(qh);
ds@1952: m_pFunction->PushString(qh == BAD_HANDLE ? error : "");
ds@1952: m_pFunction->PushCell(m_Data);
ds@1952: m_pFunction->Execute(NULL);
ds@1952:
ds@1952: if (qh != BAD_HANDLE)
ds@1952: {
ds@1952: g_HandleSys.FreeHandle(qh, &sec);
ds@1952: }
ds@1952: }
ds@1952: void Destroy()
ds@1952: {
ds@1952: delete this;
ds@1952: }
ds@1952: private:
ds@1952: IDatabase *m_pDatabase;
ds@1952: IPluginFunction *m_pFunction;
ds@1952: String m_Query;
ds@1952: cell_t m_Data;
ds@1952: CPlugin *me;
ds@1952: IQuery *m_pQuery;
ds@1952: char error[255];
ds@1952: Handle_t m_MyHandle;
ds@1952: };
ds@1952:
ds@1952: class TConnectOp : public IDBThreadOperation
ds@1952: {
ds@1952: public:
ds@1952: TConnectOp(IPluginFunction *func, IDBDriver *driver, const char *_dbname, cell_t data)
ds@1952: {
ds@1952: m_pFunction = func;
ds@1952: m_pDriver = driver;
ds@1952: m_pDatabase = NULL;
ds@1952: m_Data = data;
ds@1952: error[0] = '\0';
ds@1952: strncopy(dbname, _dbname, sizeof(dbname));
ds@1952: me = g_PluginSys.GetPluginByCtx(m_pFunction->GetParentContext()->GetContext());
ds@1952: }
ds@1952: IdentityToken_t *GetOwner()
ds@1952: {
ds@1952: return me->GetIdentity();
ds@1952: }
ds@1952: IDBDriver *GetDriver()
ds@1952: {
ds@1952: return m_pDriver;
ds@1952: }
ds@1952: void RunThreadPart()
ds@1952: {
ds@1952: g_DBMan.LockConfig();
ds@1952: const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(dbname);
ds@1952: if (!pInfo)
ds@1952: {
ds@1952: UTIL_Format(error, sizeof(error), "Could not find database config \"%s\"", dbname);
ds@1952: } else {
ds@1952: m_pDatabase = m_pDriver->Connect(pInfo, false, error, sizeof(error));
ds@1952: }
ds@1952: g_DBMan.UnlockConfig();
ds@1952: }
ds@1952: void CancelThinkPart()
ds@1952: {
ds@1952: if (m_pDatabase)
ds@1952: {
ds@1952: m_pDatabase->Close();
ds@1952: }
ds@1952: m_pFunction->PushCell(BAD_HANDLE);
ds@1952: m_pFunction->PushCell(BAD_HANDLE);
ds@1952: m_pFunction->PushString("Driver is unloading");
ds@1952: m_pFunction->PushCell(m_Data);
ds@1952: m_pFunction->Execute(NULL);
ds@1952: }
ds@1952: void RunThinkPart()
ds@1952: {
ds@1952: Handle_t hndl = BAD_HANDLE;
ds@1952:
ds@1952: if (m_pDatabase)
ds@1952: {
ds@1952: if ((hndl = g_DBMan.CreateHandle(DBHandle_Database, m_pDatabase, me->GetIdentity()))
ds@1952: == BAD_HANDLE)
ds@1952: {
ds@1952: m_pDatabase->Close();
ds@1952: UTIL_Format(error, sizeof(error), "Unable to allocate Handle");
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: m_pFunction->PushCell(m_pDriver->GetHandle());
ds@1952: m_pFunction->PushCell(hndl);
ds@1952: m_pFunction->PushString(hndl == BAD_HANDLE ? error : "");
ds@1952: m_pFunction->PushCell(m_Data);
ds@1952: m_pFunction->Execute(NULL);
ds@1952: }
ds@1952: void Destroy()
ds@1952: {
ds@1952: delete this;
ds@1952: }
ds@1952: private:
ds@1952: CPlugin *me;
ds@1952: IPluginFunction *m_pFunction;
ds@1952: IDBDriver *m_pDriver;
ds@1952: IDatabase *m_pDatabase;
ds@1952: char dbname[64];
ds@1952: char error[255];
ds@1952: cell_t m_Data;
ds@1952: };
ds@1952:
ds@1952: static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: char *conf, *err;
ds@1952:
ds@1952: size_t maxlength = (size_t)params[4];
ds@1952: bool persistent = params[2] ? true : false;
ds@1952: pContext->LocalToString(params[1], &conf);
ds@1952: pContext->LocalToString(params[3], &err);
ds@1952:
ds@1952: IDBDriver *driver;
ds@1952: IDatabase *db;
ds@1952: if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
ds@1952: {
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
ds@1952: if (!hndl)
ds@1952: {
ds@1952: db->Close();
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: /* HACK! Add us to the dependency list */
ds@1952: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
ds@1952: if (pExt)
ds@1952: {
dvander@2086: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext()));
ds@1952: }
ds@1952:
ds@1952: return hndl;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_TConnect(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IPluginFunction *pf = pContext->GetFunctionById(params[1]);
ds@1952: if (!pf)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
ds@1952: }
ds@1952:
ds@1952: char *conf;
ds@1952: pContext->LocalToString(params[2], &conf);
ds@1952:
ds@1952: IDBDriver *driver = NULL;
ds@1952: const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(conf);
ds@1952: char error[255];
ds@1952: if (pInfo != NULL)
ds@1952: {
ds@1952: if (pInfo->driver[0] == '\0')
ds@1952: {
ds@1952: driver = g_DBMan.GetDefaultDriver();
ds@1952: } else {
ds@1952: driver = g_DBMan.FindOrLoadDriver(pInfo->driver);
ds@1952: }
ds@1952: if (!driver)
ds@1952: {
ds@1952: UTIL_Format(error,
ds@1952: sizeof(error),
ds@1952: "Could not find driver \"%s\"",
ds@1952: pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName() : pInfo->driver);
ds@1952: } else if (!driver->IsThreadSafe()) {
ds@1952: UTIL_Format(error,
ds@1952: sizeof(error),
ds@1952: "Driver \"%s\" is not thread safe!",
ds@1952: driver->GetIdentifier());
ds@1952: }
ds@1952: } else {
ds@1952: UTIL_Format(error, sizeof(error), "Could not find database conf \"%s\"", conf);
ds@1952: }
ds@1952:
ds@1952: if (!pInfo || !driver)
ds@1952: {
ds@1952: pf->PushCell(BAD_HANDLE);
ds@1952: pf->PushCell(BAD_HANDLE);
ds@1952: pf->PushString(error);
ds@1952: pf->PushCell(0);
ds@1952: pf->Execute(NULL);
ds@1952: return 0;
ds@1952: }
ds@1952:
ds@1952: /* HACK! Add us to the dependency list */
ds@1952: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
ds@1952: if (pExt)
ds@1952: {
dvander@2086: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext()));
ds@1952: }
ds@1952:
ds@1952: /* Finally, add to the thread if we can */
ds@1952: TConnectOp *op = new TConnectOp(pf, driver, conf, params[3]);
ds@1952: CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
ds@1952: if (pPlugin->GetProperty("DisallowDBThreads", NULL)
ds@1952: || !g_DBMan.AddToThreadQueue(op, PrioQueue_High))
ds@1952: {
ds@1952: /* Do everything right now */
ds@1952: op->RunThreadPart();
ds@1952: op->RunThinkPart();
ds@1952: op->Destroy();
ds@1952: }
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDBDriver *driver;
ds@1952: if (params[1] == BAD_HANDLE)
ds@1952: {
ds@1952: if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Could not find any default driver");
ds@1952: }
ds@1952: } else {
ds@1952: HandleError err;
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: char *host, *user, *pass, *database, *error;
ds@1952: size_t maxlength = (size_t)params[7];
ds@1952: bool persistent = params[8] ? true : false;
ds@1952: unsigned int port = params[9];
ds@1952: unsigned int maxTimeout = params[10];
ds@1952: pContext->LocalToString(params[2], &host);
ds@1952: pContext->LocalToString(params[3], &user);
ds@1952: pContext->LocalToString(params[4], &pass);
ds@1952: pContext->LocalToString(params[5], &database);
ds@1952: pContext->LocalToString(params[6], &error);
ds@1952:
ds@1952: DatabaseInfo info;
ds@1952: info.database = database;
ds@1952: info.driver = driver->GetIdentifier();
ds@1952: info.host = host;
ds@1952: info.maxTimeout = maxTimeout;
ds@1952: info.pass = pass;
ds@1952: info.port = port;
ds@1952: info.user = user;
ds@1952:
ds@1952: IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
ds@1952:
ds@1952: if (db)
ds@1952: {
ds@1952: Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
ds@1952: if (!hndl)
ds@1952: {
ds@1952: db->Close();
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: /* HACK! Add us to the dependency list */
ds@1952: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
ds@1952: if (pExt)
ds@1952: {
dvander@2086: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext()));
ds@1952: }
ds@1952:
ds@1952: return hndl;
ds@1952: }
ds@1952:
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDBDriver *driver;
ds@1952: if (params[1] == BAD_HANDLE)
ds@1952: {
ds@1952: if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Could not find any default driver");
ds@1952: }
ds@1952: } else {
ds@1952: HandleError err;
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: char *name;
ds@1952: pContext->LocalToString(params[1], &name);
ds@1952:
ds@1952: IDBDriver *driver = NULL;
ds@1952: if (name[0] == '\0')
ds@1952: {
ds@1952: driver = g_DBMan.GetDefaultDriver();
ds@1952: } else {
ds@1952: driver = g_DBMan.FindOrLoadDriver(name);
ds@1952: }
ds@1952:
ds@1952: return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDBDriver *driver;
ds@1952: if (params[1] == BAD_HANDLE)
ds@1952: {
ds@1952: if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Could not find any default driver");
ds@1952: }
ds@1952: } else {
ds@1952: HandleError err;
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: IPreparedQuery *stmt = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: if (db)
ds@1952: {
ds@1952: return db->GetAffectedRows();
ds@1952: } else if (stmt) {
ds@1952: return stmt->GetAffectedRows();
ds@1952: }
ds@1952:
ds@1952: return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: IPreparedQuery *stmt = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: if (db)
ds@1952: {
ds@1952: return db->GetInsertID();
ds@1952: } else if (stmt) {
ds@1952: return stmt->GetInsertID();
ds@1952: }
ds@1952:
ds@1952: return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: IPreparedQuery *stmt = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: const char *error = "";
ds@1952: if (db)
ds@1952: {
ds@1952: error = db->GetError();
ds@1952: } else if (stmt) {
ds@1952: error = stmt->GetError();
ds@1952: }
ds@1952:
ds@1952: if (error[0] == '\0')
ds@1952: {
ds@1952: return false;
ds@1952: }
ds@1952:
ds@1952: pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: char *input, *output;
ds@1952: size_t maxlength = (size_t)params[4];
ds@1952: pContext->LocalToString(params[2], &input);
ds@1952: pContext->LocalToString(params[3], &output);
ds@1952:
ds@1952: size_t written;
ds@1952: bool s = db->QuoteString(input, output, maxlength, &written);
ds@1952:
ds@1952: cell_t *addr;
ds@1952: pContext->LocalToPhysAddr(params[5], &addr);
ds@1952: *addr = (cell_t)written;
ds@1952:
ds@1952: return s ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: char *query;
ds@1952: pContext->LocalToString(params[2], &query);
ds@1952:
ds@1952: if (params[0] >= 3 && params[3] != -1)
ds@1952: {
ds@1952: return db->DoSimpleQueryEx(query, params[3]) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: return db->DoSimpleQuery(query) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: char *query;
ds@1952: pContext->LocalToString(params[2], &query);
ds@1952:
ds@1952: IQuery *qr;
ds@1952:
ds@1952: if (params[0] >= 3 && params[3] != -1)
ds@1952: {
ds@1952: qr = db->DoQueryEx(query, params[3]);
ds@1952: }
ds@1952: else
ds@1952: {
ds@1952: qr = db->DoQuery(query);
ds@1952: }
ds@1952:
ds@1952: if (!qr)
ds@1952: {
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
ds@1952: if (hndl == BAD_HANDLE)
ds@1952: {
ds@1952: qr->Destroy();
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: return hndl;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_TQuery(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: if (!db->GetDriver()->IsThreadSafe())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Driver \"%s\" is not thread safe!", db->GetDriver()->GetIdentifier());
ds@1952: }
ds@1952:
ds@1952: IPluginFunction *pf = pContext->GetFunctionById(params[2]);
ds@1952: if (!pf)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
ds@1952: }
ds@1952:
ds@1952: char *query;
ds@1952: pContext->LocalToString(params[3], &query);
ds@1952:
ds@1952: cell_t data = params[4];
ds@1952: PrioQueueLevel level = PrioQueue_Normal;
ds@1952: if (params[5] == (cell_t)PrioQueue_High)
ds@1952: {
ds@1952: level = PrioQueue_High;
ds@1952: } else if (params[5] == (cell_t)PrioQueue_Low) {
ds@1952: level = PrioQueue_Low;
ds@1952: }
ds@1952:
ds@1952: CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
ds@1952:
ds@1952: TQueryOp *op = new TQueryOp(db, pf, query, data);
ds@1952: if (pPlugin->GetProperty("DisallowDBThreads", NULL)
ds@1952: || !g_DBMan.AddToThreadQueue(op, level))
ds@1952: {
ds@1952: /* Do everything right now */
ds@1952: op->RunThreadPart();
ds@1952: op->RunThinkPart();
ds@1952: op->Destroy();
ds@1952: }
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_LockDatabase(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: db->LockForFullAtomicOperation();
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_UnlockDatabase(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: db->UnlockFromFullAtomicOperation();
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db = NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: char *query, *error;
ds@1952: size_t maxlength = (size_t)params[4];
ds@1952: pContext->LocalToString(params[2], &query);
ds@1952: pContext->LocalToString(params[3], &error);
ds@1952:
ds@1952: IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
ds@1952:
ds@1952: if (!qr)
ds@1952: {
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: Handle_t hndl = g_HandleSys.CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
ds@1952: if (hndl == BAD_HANDLE)
ds@1952: {
ds@1952: qr->Destroy();
ds@1952: return BAD_HANDLE;
ds@1952: }
ds@1952:
ds@1952: return hndl;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: return query->FetchMoreResults() ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: return query->GetResultSet() != NULL ? true : false;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return 0;
ds@1952: }
ds@1952:
ds@1952: return rs->GetRowCount();
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return 0;
ds@1952: }
ds@1952:
ds@1952: return rs->GetFieldCount();
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: unsigned int field = params[2];
ds@1952:
ds@1952: const char *fldname;
ds@1952: if ((fldname = rs->FieldNumToName(field)) == NULL)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid field index %d", field);
ds@1952: }
ds@1952:
ds@1952: pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: char *field;
ds@1952: pContext->LocalToString(params[2], &field);
ds@1952:
ds@1952: cell_t *num;
ds@1952: pContext->LocalToPhysAddr(params[3], &num);
ds@1952:
ds@1952: return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: return (rs->FetchRow() != NULL) ? true : false;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: return rs->MoreRows() ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: return rs->Rewind() ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: IResultRow *row = rs->CurrentRow();
ds@1952: if (!row)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952: }
ds@1952:
ds@1952: const char *str;
ds@1952: size_t length;
ds@1952: DBResult res = row->GetString(params[2], &str, &length);
ds@1952:
ds@1952: if (res == DBVal_Error)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
ds@1952: } else if (res == DBVal_TypeMismatch) {
ds@1952: return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
ds@1952: }
ds@1952:
ds@1952: pContext->StringToLocalUTF8(params[3], params[4], str, &length);
ds@1952:
ds@1952: cell_t *addr;
ds@1952: pContext->LocalToPhysAddr(params[5], &addr);
ds@1952: *addr = (cell_t)res;
ds@1952:
ds@1952: return (cell_t)length;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: IResultRow *row = rs->CurrentRow();
ds@1952: if (!row)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952: }
ds@1952:
ds@1952: float f;
ds@1952: DBResult res = row->GetFloat(params[2], &f);
ds@1952:
ds@1952: if (res == DBVal_Error)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
ds@1952: } else if (res == DBVal_TypeMismatch) {
ds@1952: return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
ds@1952: }
ds@1952:
ds@1952: cell_t *addr;
ds@1952: pContext->LocalToPhysAddr(params[3], &addr);
ds@1952: *addr = (cell_t)res;
ds@1952:
ds@1952: return sp_ftoc(f);
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: IResultRow *row = rs->CurrentRow();
ds@1952: if (!row)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952: }
ds@1952:
ds@1952: int iv;
ds@1952: DBResult res = row->GetInt(params[2], &iv);
ds@1952:
ds@1952: if (res == DBVal_Error)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
ds@1952: } else if (res == DBVal_TypeMismatch) {
ds@1952: return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
ds@1952: }
ds@1952:
ds@1952: cell_t *addr;
ds@1952: pContext->LocalToPhysAddr(params[3], &addr);
ds@1952: *addr = (cell_t)res;
ds@1952:
ds@1952: return iv;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: IResultRow *row = rs->CurrentRow();
ds@1952: if (!row)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952: }
ds@1952:
ds@1952: if ((unsigned)params[2] >= rs->GetFieldCount())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid field index %d", params[2]);
ds@1952: }
ds@1952:
ds@1952: return row->IsNull(params[2]) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IQuery *query;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IResultSet *rs = query->GetResultSet();
ds@1952: if (!rs)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("No current result set");
ds@1952: }
ds@1952:
ds@1952: IResultRow *row = rs->CurrentRow();
ds@1952: if (!row)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952: }
ds@1952:
ds@1952: if ((unsigned)params[2] >= rs->GetFieldCount())
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid field index %d", params[2]);
ds@1952: }
ds@1952:
ds@1952: return row->GetDataSize(params[2]);
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IPreparedQuery *stmt;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
ds@1952: }
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IPreparedQuery *stmt;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
ds@1952: }
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IPreparedQuery *stmt;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: char *str;
ds@1952: pContext->LocalToString(params[3], &str);
ds@1952:
ds@1952: if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
ds@1952: }
ds@1952:
ds@1952: return 1;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IPreparedQuery *stmt;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: return stmt->Execute() ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_IsSameConnection(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db1=NULL, *db2=NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[2], DBHandle_Database, (void **)&db2))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle 2/%x (error: %d)", params[2], err);
ds@1952: }
ds@1952:
ds@1952: return (db1 == db2) ? true : false;
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_ReadDriver(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: IDatabase *db1=NULL;
ds@1952: HandleError err;
ds@1952:
ds@1952: if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
ds@1952: != HandleError_None)
ds@1952: {
ds@1952: return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
ds@1952: }
ds@1952:
ds@1952: IDBDriver *driver = db1->GetDriver();
ds@1952:
ds@1952: pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
ds@1952:
ds@1952: return driver->GetHandle();
ds@1952: }
ds@1952:
ds@1952: static cell_t SQL_CheckConfig(IPluginContext *pContext, const cell_t *params)
ds@1952: {
ds@1952: char *name;
ds@1952: pContext->LocalToString(params[1], &name);
ds@1952:
ds@1952: return (g_DBMan.FindDatabaseConf(name) != NULL) ? 1 : 0;
ds@1952: }
ds@1952:
ds@1952: REGISTER_NATIVES(dbNatives)
ds@1952: {
ds@1952: {"SQL_BindParamInt", SQL_BindParamInt},
ds@1952: {"SQL_BindParamFloat", SQL_BindParamFloat},
ds@1952: {"SQL_BindParamString", SQL_BindParamString},\
ds@1952: {"SQL_CheckConfig", SQL_CheckConfig},
ds@1952: {"SQL_Connect", SQL_Connect},
ds@1952: {"SQL_ConnectEx", SQL_ConnectEx},
ds@1952: {"SQL_EscapeString", SQL_QuoteString},
ds@1952: {"SQL_Execute", SQL_Execute},
ds@1952: {"SQL_FastQuery", SQL_FastQuery},
ds@1952: {"SQL_FetchFloat", SQL_FetchFloat},
ds@1952: {"SQL_FetchInt", SQL_FetchInt},
ds@1952: {"SQL_FetchMoreResults", SQL_FetchMoreResults},
ds@1952: {"SQL_FetchRow", SQL_FetchRow},
ds@1952: {"SQL_FetchSize", SQL_FetchSize},
ds@1952: {"SQL_FetchString", SQL_FetchString},
ds@1952: {"SQL_FieldNameToNum", SQL_FieldNameToNum},
ds@1952: {"SQL_FieldNumToName", SQL_FieldNumToName},
ds@1952: {"SQL_GetAffectedRows", SQL_GetAffectedRows},
ds@1952: {"SQL_GetDriver", SQL_GetDriver},
ds@1952: {"SQL_GetDriverIdent", SQL_GetDriverIdent},
ds@1952: {"SQL_GetDriverProduct", SQL_GetDriverProduct},
ds@1952: {"SQL_GetError", SQL_GetError},
ds@1952: {"SQL_GetFieldCount", SQL_GetFieldCount},
ds@1952: {"SQL_GetInsertId", SQL_GetInsertId},
ds@1952: {"SQL_GetRowCount", SQL_GetRowCount},
ds@1952: {"SQL_HasResultSet", SQL_HasResultSet},
ds@1952: {"SQL_IsFieldNull", SQL_IsFieldNull},
ds@1952: {"SQL_IsSameConnection", SQL_IsSameConnection},
ds@1952: {"SQL_LockDatabase", SQL_LockDatabase},
ds@1952: {"SQL_MoreRows", SQL_MoreRows},
ds@1952: {"SQL_PrepareQuery", SQL_PrepareQuery},
ds@1952: {"SQL_Query", SQL_Query},
ds@1952: {"SQL_QuoteString", SQL_QuoteString},
ds@1952: {"SQL_ReadDriver", SQL_ReadDriver},
ds@1952: {"SQL_Rewind", SQL_Rewind},
ds@1952: {"SQL_TConnect", SQL_TConnect},
ds@1952: {"SQL_TQuery", SQL_TQuery},
ds@1952: {"SQL_UnlockDatabase", SQL_UnlockDatabase},
ds@1952: {NULL, NULL},
ds@1952: };