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 "HandleSys.h" dvander@868: #include "Database.h" dvander@868: #include "ExtensionSys.h" dvander@868: #include "PluginSys.h" dvander@1096: #include "sm_stringutil.h" dvander@868: dvander@868: HandleType_t hQueryType; dvander@868: HandleType_t hStmtType; dvander@868: 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@868: g_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@868: g_HandleSys.InitAccessDefaults(&tacc, NULL); dvander@868: tacc.ident = g_pCoreIdent; dvander@868: dvander@868: hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL); dvander@869: hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, g_pCoreIdent, NULL); dvander@868: } dvander@868: dvander@868: virtual void OnSourceModShutdown() dvander@868: { dvander@868: g_HandleSys.RemoveType(hStmtType, g_pCoreIdent); dvander@868: g_HandleSys.RemoveType(hQueryType, g_pCoreIdent); dvander@868: } dvander@868: dvander@868: virtual void OnHandleDestroy(HandleType_t type, void *object) dvander@868: { dvander@868: if (type == hQueryType) dvander@868: { dvander@868: IQuery *query = (IQuery *)object; dvander@868: query->Destroy(); 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; dvander@868: sec.pOwner = pContext->GetIdentity(); dvander@868: sec.pIdentity = g_pCoreIdent; dvander@868: dvander@868: return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query); 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@868: return g_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@1096: me(g_PluginSys.GetPluginByCtx(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@1096: g_HandleSys.InitAccessDefaults(NULL, &access); dvander@1096: access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; dvander@1096: m_MyHandle = g_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@1096: g_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@1096: g_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: { dvander@1096: qh = g_HandleSys.CreateHandle(hQueryType, m_pQuery, 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"); 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@1096: g_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@1096: CPlugin *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@1096: me = g_PluginSys.GetPluginByCtx(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@1096: CPlugin *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@868: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); dvander@868: if (pExt) dvander@868: { dvander@2086: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(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@1096: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); dvander@1096: if (pExt) dvander@1096: { dvander@2086: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(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@1096: CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(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@868: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); dvander@868: if (pExt) dvander@868: { dvander@2086: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(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; 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: if (db) dvander@868: { dvander@868: return db->GetAffectedRows(); dvander@868: } else if (stmt) { dvander@868: return stmt->GetAffectedRows(); dvander@868: } dvander@868: dvander@868: return pContext->ThrowNativeError("Unknown error reading db/stmt 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; 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: if (db) dvander@868: { dvander@868: return db->GetInsertID(); dvander@868: } else if (stmt) { dvander@868: return stmt->GetInsertID(); dvander@868: } dvander@868: dvander@868: return pContext->ThrowNativeError("Unknown error reading db/stmt 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: { 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 *input, *output; dvander@868: 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; dvander@868: 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: dvander@868: Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, 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@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@1096: CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(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@868: Handle_t hndl = g_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@2357: CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); dvander@2357: if (pExt) dvander@2357: { dvander@2357: g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); dvander@2357: } dvander@2357: dvander@2357: return hndl; dvander@2357: } dvander@2357: 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}, dvander@868: {NULL, NULL}, dvander@868: }; dvander@2357: