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