1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/smn_database.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,1321 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include "sm_globals.h"
1.36 +#include "HandleSys.h"
1.37 +#include "Database.h"
1.38 +#include "ExtensionSys.h"
1.39 +#include "PluginSys.h"
1.40 +#include "sm_stringutil.h"
1.41 +
1.42 +HandleType_t hQueryType;
1.43 +HandleType_t hStmtType;
1.44 +
1.45 +class DatabaseHelpers :
1.46 + public SMGlobalClass,
1.47 + public IHandleTypeDispatch
1.48 +{
1.49 +public:
1.50 + virtual void OnSourceModAllInitialized()
1.51 + {
1.52 + HandleAccess acc;
1.53 +
1.54 + /* Disable cloning */
1.55 + g_HandleSys.InitAccessDefaults(NULL, &acc);
1.56 + acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
1.57 +
1.58 + TypeAccess tacc;
1.59 +
1.60 + g_HandleSys.InitAccessDefaults(&tacc, NULL);
1.61 + tacc.ident = g_pCoreIdent;
1.62 +
1.63 + hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
1.64 + hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, g_pCoreIdent, NULL);
1.65 + }
1.66 +
1.67 + virtual void OnSourceModShutdown()
1.68 + {
1.69 + g_HandleSys.RemoveType(hStmtType, g_pCoreIdent);
1.70 + g_HandleSys.RemoveType(hQueryType, g_pCoreIdent);
1.71 + }
1.72 +
1.73 + virtual void OnHandleDestroy(HandleType_t type, void *object)
1.74 + {
1.75 + if (type == hQueryType)
1.76 + {
1.77 + IQuery *query = (IQuery *)object;
1.78 + query->Destroy();
1.79 + } else if (type == hStmtType) {
1.80 + IPreparedQuery *query = (IPreparedQuery *)object;
1.81 + query->Destroy();
1.82 + }
1.83 + }
1.84 +} s_DatabaseNativeHelpers;
1.85 +
1.86 +//is this safe for stmt handles? i think since it's single inheritance, it always will be.
1.87 +inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
1.88 +{
1.89 + HandleSecurity sec;
1.90 + sec.pOwner = pContext->GetIdentity();
1.91 + sec.pIdentity = g_pCoreIdent;
1.92 +
1.93 + return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query);
1.94 +}
1.95 +
1.96 +inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
1.97 +{
1.98 + HandleSecurity sec;
1.99 + sec.pOwner = pContext->GetIdentity();
1.100 + sec.pIdentity = g_pCoreIdent;
1.101 +
1.102 + return g_HandleSys.ReadHandle(hndl, hStmtType, &sec, (void **)query);
1.103 +}
1.104 +
1.105 +inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
1.106 +{
1.107 + HandleError err;
1.108 + if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
1.109 + {
1.110 + *db = NULL;
1.111 + return ReadStmtHndl(hndl, pContext, query);
1.112 + }
1.113 + return err;
1.114 +}
1.115 +
1.116 +class TQueryOp : public IDBThreadOperation
1.117 +{
1.118 +public:
1.119 + TQueryOp(IDatabase *db, IPluginFunction *pf, const char *query, cell_t data) :
1.120 + m_pDatabase(db), m_pFunction(pf), m_Query(query), m_Data(data),
1.121 + me(g_PluginSys.GetPluginByCtx(pf->GetParentContext()->GetContext())),
1.122 + m_pQuery(NULL)
1.123 + {
1.124 + /* We always increase the reference count because this is potentially
1.125 + * asynchronous. Otherwise the original handle could be closed while
1.126 + * we're still latched onto it.
1.127 + */
1.128 + m_pDatabase->IncReferenceCount();
1.129 +
1.130 + /* Now create our own Handle such that it can only be closed by us.
1.131 + * We allow cloning just in case someone wants to hold onto it.
1.132 + */
1.133 + HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
1.134 + HandleAccess access;
1.135 + g_HandleSys.InitAccessDefaults(NULL, &access);
1.136 + access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
1.137 + m_MyHandle = g_HandleSys.CreateHandleEx(g_DBMan.GetDatabaseType(),
1.138 + db,
1.139 + &sec,
1.140 + &access,
1.141 + NULL);
1.142 + }
1.143 + ~TQueryOp()
1.144 + {
1.145 + if (m_pQuery)
1.146 + {
1.147 + m_pQuery->Destroy();
1.148 + }
1.149 +
1.150 + /* Close our Handle if it's valid. */
1.151 + if (m_MyHandle != BAD_HANDLE)
1.152 + {
1.153 + HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
1.154 + g_HandleSys.FreeHandle(m_MyHandle, &sec);
1.155 + } else {
1.156 + /* Otherwise, there is an open ref to the db */
1.157 + m_pDatabase->Close();
1.158 + }
1.159 + }
1.160 + IdentityToken_t *GetOwner()
1.161 + {
1.162 + return me->GetIdentity();
1.163 + }
1.164 + IDBDriver *GetDriver()
1.165 + {
1.166 + return m_pDatabase->GetDriver();
1.167 + }
1.168 + void RunThreadPart()
1.169 + {
1.170 + m_pDatabase->LockForFullAtomicOperation();
1.171 + m_pQuery = m_pDatabase->DoQuery(m_Query.c_str());
1.172 + if (!m_pQuery)
1.173 + {
1.174 + UTIL_Format(error, sizeof(error), "%s", m_pDatabase->GetError());
1.175 + }
1.176 + m_pDatabase->UnlockFromFullAtomicOperation();
1.177 + }
1.178 + void CancelThinkPart()
1.179 + {
1.180 + m_pFunction->PushCell(BAD_HANDLE);
1.181 + m_pFunction->PushCell(BAD_HANDLE);
1.182 + m_pFunction->PushString("Driver is unloading");
1.183 + m_pFunction->PushCell(m_Data);
1.184 + m_pFunction->Execute(NULL);
1.185 + }
1.186 + void RunThinkPart()
1.187 + {
1.188 + /* Create a Handle for our query */
1.189 + HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
1.190 + HandleAccess access;
1.191 + g_HandleSys.InitAccessDefaults(NULL, &access);
1.192 + access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
1.193 +
1.194 + Handle_t qh = BAD_HANDLE;
1.195 +
1.196 + if (m_pQuery)
1.197 + {
1.198 + qh = g_HandleSys.CreateHandle(hQueryType, m_pQuery, me->GetIdentity(), g_pCoreIdent, NULL);
1.199 + if (qh != BAD_HANDLE)
1.200 + {
1.201 + m_pQuery = NULL;
1.202 + } else {
1.203 + UTIL_Format(error, sizeof(error), "Could not alloc handle");
1.204 + }
1.205 + }
1.206 +
1.207 + m_pFunction->PushCell(m_MyHandle);
1.208 + m_pFunction->PushCell(qh);
1.209 + m_pFunction->PushString(qh == BAD_HANDLE ? error : "");
1.210 + m_pFunction->PushCell(m_Data);
1.211 + m_pFunction->Execute(NULL);
1.212 +
1.213 + if (qh != BAD_HANDLE)
1.214 + {
1.215 + g_HandleSys.FreeHandle(qh, &sec);
1.216 + }
1.217 + }
1.218 + void Destroy()
1.219 + {
1.220 + delete this;
1.221 + }
1.222 +private:
1.223 + IDatabase *m_pDatabase;
1.224 + IPluginFunction *m_pFunction;
1.225 + String m_Query;
1.226 + cell_t m_Data;
1.227 + CPlugin *me;
1.228 + IQuery *m_pQuery;
1.229 + char error[255];
1.230 + Handle_t m_MyHandle;
1.231 +};
1.232 +
1.233 +class TConnectOp : public IDBThreadOperation
1.234 +{
1.235 +public:
1.236 + TConnectOp(IPluginFunction *func, IDBDriver *driver, const char *_dbname, cell_t data)
1.237 + {
1.238 + m_pFunction = func;
1.239 + m_pDriver = driver;
1.240 + m_pDatabase = NULL;
1.241 + m_Data = data;
1.242 + error[0] = '\0';
1.243 + strncopy(dbname, _dbname, sizeof(dbname));
1.244 + me = g_PluginSys.GetPluginByCtx(m_pFunction->GetParentContext()->GetContext());
1.245 + }
1.246 + IdentityToken_t *GetOwner()
1.247 + {
1.248 + return me->GetIdentity();
1.249 + }
1.250 + IDBDriver *GetDriver()
1.251 + {
1.252 + return m_pDriver;
1.253 + }
1.254 + void RunThreadPart()
1.255 + {
1.256 + g_DBMan.LockConfig();
1.257 + const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(dbname);
1.258 + if (!pInfo)
1.259 + {
1.260 + UTIL_Format(error, sizeof(error), "Could not find database config \"%s\"", dbname);
1.261 + } else {
1.262 + m_pDatabase = m_pDriver->Connect(pInfo, false, error, sizeof(error));
1.263 + }
1.264 + g_DBMan.UnlockConfig();
1.265 + }
1.266 + void CancelThinkPart()
1.267 + {
1.268 + if (m_pDatabase)
1.269 + {
1.270 + m_pDatabase->Close();
1.271 + }
1.272 + m_pFunction->PushCell(BAD_HANDLE);
1.273 + m_pFunction->PushCell(BAD_HANDLE);
1.274 + m_pFunction->PushString("Driver is unloading");
1.275 + m_pFunction->PushCell(m_Data);
1.276 + m_pFunction->Execute(NULL);
1.277 + }
1.278 + void RunThinkPart()
1.279 + {
1.280 + Handle_t hndl = BAD_HANDLE;
1.281 +
1.282 + if (m_pDatabase)
1.283 + {
1.284 + if ((hndl = g_DBMan.CreateHandle(DBHandle_Database, m_pDatabase, me->GetIdentity()))
1.285 + == BAD_HANDLE)
1.286 + {
1.287 + m_pDatabase->Close();
1.288 + UTIL_Format(error, sizeof(error), "Unable to allocate Handle");
1.289 + }
1.290 + }
1.291 +
1.292 + m_pFunction->PushCell(m_pDriver->GetHandle());
1.293 + m_pFunction->PushCell(hndl);
1.294 + m_pFunction->PushString(hndl == BAD_HANDLE ? error : "");
1.295 + m_pFunction->PushCell(m_Data);
1.296 + m_pFunction->Execute(NULL);
1.297 + }
1.298 + void Destroy()
1.299 + {
1.300 + delete this;
1.301 + }
1.302 +private:
1.303 + CPlugin *me;
1.304 + IPluginFunction *m_pFunction;
1.305 + IDBDriver *m_pDriver;
1.306 + IDatabase *m_pDatabase;
1.307 + char dbname[64];
1.308 + char error[255];
1.309 + cell_t m_Data;
1.310 +};
1.311 +
1.312 +static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
1.313 +{
1.314 + char *conf, *err;
1.315 +
1.316 + size_t maxlength = (size_t)params[4];
1.317 + bool persistent = params[2] ? true : false;
1.318 + pContext->LocalToString(params[1], &conf);
1.319 + pContext->LocalToString(params[3], &err);
1.320 +
1.321 + IDBDriver *driver;
1.322 + IDatabase *db;
1.323 + if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
1.324 + {
1.325 + return BAD_HANDLE;
1.326 + }
1.327 +
1.328 + Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
1.329 + if (!hndl)
1.330 + {
1.331 + db->Close();
1.332 + return BAD_HANDLE;
1.333 + }
1.334 +
1.335 + /* HACK! Add us to the dependency list */
1.336 + CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
1.337 + if (pExt)
1.338 + {
1.339 + g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
1.340 + }
1.341 +
1.342 + return hndl;
1.343 +}
1.344 +
1.345 +static cell_t SQL_TConnect(IPluginContext *pContext, const cell_t *params)
1.346 +{
1.347 + IPluginFunction *pf = pContext->GetFunctionById(params[1]);
1.348 + if (!pf)
1.349 + {
1.350 + return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
1.351 + }
1.352 +
1.353 + char *conf;
1.354 + pContext->LocalToString(params[2], &conf);
1.355 +
1.356 + IDBDriver *driver = NULL;
1.357 + const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(conf);
1.358 + char error[255];
1.359 + if (pInfo != NULL)
1.360 + {
1.361 + if (pInfo->driver[0] == '\0')
1.362 + {
1.363 + driver = g_DBMan.GetDefaultDriver();
1.364 + } else {
1.365 + driver = g_DBMan.FindOrLoadDriver(pInfo->driver);
1.366 + }
1.367 + if (!driver)
1.368 + {
1.369 + UTIL_Format(error,
1.370 + sizeof(error),
1.371 + "Could not find driver \"%s\"",
1.372 + pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName() : pInfo->driver);
1.373 + } else if (!driver->IsThreadSafe()) {
1.374 + UTIL_Format(error,
1.375 + sizeof(error),
1.376 + "Driver \"%s\" is not thread safe!",
1.377 + driver->GetIdentifier());
1.378 + }
1.379 + } else {
1.380 + UTIL_Format(error, sizeof(error), "Could not find database conf \"%s\"", conf);
1.381 + }
1.382 +
1.383 + if (!pInfo || !driver)
1.384 + {
1.385 + pf->PushCell(BAD_HANDLE);
1.386 + pf->PushCell(BAD_HANDLE);
1.387 + pf->PushString(error);
1.388 + pf->PushCell(0);
1.389 + pf->Execute(NULL);
1.390 + return 0;
1.391 + }
1.392 +
1.393 + /* HACK! Add us to the dependency list */
1.394 + CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
1.395 + if (pExt)
1.396 + {
1.397 + g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
1.398 + }
1.399 +
1.400 + /* Finally, add to the thread if we can */
1.401 + TConnectOp *op = new TConnectOp(pf, driver, conf, params[3]);
1.402 + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
1.403 + if (pPlugin->GetProperty("DisallowDBThreads", NULL)
1.404 + || !g_DBMan.AddToThreadQueue(op, PrioQueue_High))
1.405 + {
1.406 + /* Do everything right now */
1.407 + op->RunThreadPart();
1.408 + op->RunThinkPart();
1.409 + op->Destroy();
1.410 + }
1.411 +
1.412 + return 1;
1.413 +}
1.414 +
1.415 +static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
1.416 +{
1.417 + IDBDriver *driver;
1.418 + if (params[1] == BAD_HANDLE)
1.419 + {
1.420 + if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
1.421 + {
1.422 + return pContext->ThrowNativeError("Could not find any default driver");
1.423 + }
1.424 + } else {
1.425 + HandleError err;
1.426 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
1.427 + != HandleError_None)
1.428 + {
1.429 + return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
1.430 + }
1.431 + }
1.432 +
1.433 + char *host, *user, *pass, *database, *error;
1.434 + size_t maxlength = (size_t)params[7];
1.435 + bool persistent = params[8] ? true : false;
1.436 + unsigned int port = params[9];
1.437 + unsigned int maxTimeout = params[10];
1.438 + pContext->LocalToString(params[2], &host);
1.439 + pContext->LocalToString(params[3], &user);
1.440 + pContext->LocalToString(params[4], &pass);
1.441 + pContext->LocalToString(params[5], &database);
1.442 + pContext->LocalToString(params[6], &error);
1.443 +
1.444 + DatabaseInfo info;
1.445 + info.database = database;
1.446 + info.driver = driver->GetIdentifier();
1.447 + info.host = host;
1.448 + info.maxTimeout = maxTimeout;
1.449 + info.pass = pass;
1.450 + info.port = port;
1.451 + info.user = user;
1.452 +
1.453 + IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
1.454 +
1.455 + if (db)
1.456 + {
1.457 + Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
1.458 + if (!hndl)
1.459 + {
1.460 + db->Close();
1.461 + return BAD_HANDLE;
1.462 + }
1.463 +
1.464 + /* HACK! Add us to the dependency list */
1.465 + CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
1.466 + if (pExt)
1.467 + {
1.468 + g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
1.469 + }
1.470 +
1.471 + return hndl;
1.472 + }
1.473 +
1.474 + return BAD_HANDLE;
1.475 +}
1.476 +
1.477 +static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
1.478 +{
1.479 + IDBDriver *driver;
1.480 + if (params[1] == BAD_HANDLE)
1.481 + {
1.482 + if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
1.483 + {
1.484 + return pContext->ThrowNativeError("Could not find any default driver");
1.485 + }
1.486 + } else {
1.487 + HandleError err;
1.488 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
1.489 + != HandleError_None)
1.490 + {
1.491 + return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
1.492 + }
1.493 + }
1.494 +
1.495 + pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
1.496 +
1.497 + return 1;
1.498 +}
1.499 +
1.500 +static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
1.501 +{
1.502 + char *name;
1.503 + pContext->LocalToString(params[1], &name);
1.504 +
1.505 + IDBDriver *driver = NULL;
1.506 + if (name[0] == '\0')
1.507 + {
1.508 + driver = g_DBMan.GetDefaultDriver();
1.509 + } else {
1.510 + driver = g_DBMan.FindOrLoadDriver(name);
1.511 + }
1.512 +
1.513 + return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
1.514 +}
1.515 +
1.516 +static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
1.517 +{
1.518 + IDBDriver *driver;
1.519 + if (params[1] == BAD_HANDLE)
1.520 + {
1.521 + if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
1.522 + {
1.523 + return pContext->ThrowNativeError("Could not find any default driver");
1.524 + }
1.525 + } else {
1.526 + HandleError err;
1.527 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
1.528 + != HandleError_None)
1.529 + {
1.530 + return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
1.531 + }
1.532 + }
1.533 +
1.534 + pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
1.535 +
1.536 + return 1;
1.537 +}
1.538 +
1.539 +static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
1.540 +{
1.541 + IDatabase *db = NULL;
1.542 + IPreparedQuery *stmt = NULL;
1.543 + HandleError err;
1.544 +
1.545 + if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
1.546 + {
1.547 + return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
1.548 + }
1.549 +
1.550 + if (db)
1.551 + {
1.552 + return db->GetAffectedRows();
1.553 + } else if (stmt) {
1.554 + return stmt->GetAffectedRows();
1.555 + }
1.556 +
1.557 + return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
1.558 +}
1.559 +
1.560 +static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
1.561 +{
1.562 + IDatabase *db = NULL;
1.563 + IPreparedQuery *stmt = NULL;
1.564 + HandleError err;
1.565 +
1.566 + if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
1.567 + {
1.568 + return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
1.569 + }
1.570 +
1.571 + if (db)
1.572 + {
1.573 + return db->GetInsertID();
1.574 + } else if (stmt) {
1.575 + return stmt->GetInsertID();
1.576 + }
1.577 +
1.578 + return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
1.579 +}
1.580 +
1.581 +static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
1.582 +{
1.583 + IDatabase *db = NULL;
1.584 + IPreparedQuery *stmt = NULL;
1.585 + HandleError err;
1.586 +
1.587 + if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
1.588 + {
1.589 + return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
1.590 + }
1.591 +
1.592 + const char *error = "";
1.593 + if (db)
1.594 + {
1.595 + error = db->GetError();
1.596 + } else if (stmt) {
1.597 + error = stmt->GetError();
1.598 + }
1.599 +
1.600 + if (error[0] == '\0')
1.601 + {
1.602 + return false;
1.603 + }
1.604 +
1.605 + pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
1.606 +
1.607 + return 1;
1.608 +}
1.609 +
1.610 +static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
1.611 +{
1.612 + IDatabase *db = NULL;
1.613 + HandleError err;
1.614 +
1.615 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.616 + != HandleError_None)
1.617 + {
1.618 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.619 + }
1.620 +
1.621 + char *input, *output;
1.622 + size_t maxlength = (size_t)params[4];
1.623 + pContext->LocalToString(params[2], &input);
1.624 + pContext->LocalToString(params[3], &output);
1.625 +
1.626 + size_t written;
1.627 + bool s = db->QuoteString(input, output, maxlength, &written);
1.628 +
1.629 + cell_t *addr;
1.630 + pContext->LocalToPhysAddr(params[5], &addr);
1.631 + *addr = (cell_t)written;
1.632 +
1.633 + return s ? 1 : 0;
1.634 +}
1.635 +
1.636 +static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
1.637 +{
1.638 + IDatabase *db = NULL;
1.639 + HandleError err;
1.640 +
1.641 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.642 + != HandleError_None)
1.643 + {
1.644 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.645 + }
1.646 +
1.647 + char *query;
1.648 + pContext->LocalToString(params[2], &query);
1.649 +
1.650 + if (params[0] >= 3 && params[3] != -1)
1.651 + {
1.652 + return db->DoSimpleQueryEx(query, params[3]) ? 1 : 0;
1.653 + }
1.654 +
1.655 + return db->DoSimpleQuery(query) ? 1 : 0;
1.656 +}
1.657 +
1.658 +static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
1.659 +{
1.660 + IDatabase *db = NULL;
1.661 + HandleError err;
1.662 +
1.663 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.664 + != HandleError_None)
1.665 + {
1.666 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.667 + }
1.668 +
1.669 + char *query;
1.670 + pContext->LocalToString(params[2], &query);
1.671 +
1.672 + IQuery *qr;
1.673 +
1.674 + if (params[0] >= 3 && params[3] != -1)
1.675 + {
1.676 + qr = db->DoQueryEx(query, params[3]);
1.677 + }
1.678 + else
1.679 + {
1.680 + qr = db->DoQuery(query);
1.681 + }
1.682 +
1.683 + if (!qr)
1.684 + {
1.685 + return BAD_HANDLE;
1.686 + }
1.687 +
1.688 + Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
1.689 + if (hndl == BAD_HANDLE)
1.690 + {
1.691 + qr->Destroy();
1.692 + return BAD_HANDLE;
1.693 + }
1.694 +
1.695 + return hndl;
1.696 +}
1.697 +
1.698 +static cell_t SQL_TQuery(IPluginContext *pContext, const cell_t *params)
1.699 +{
1.700 + IDatabase *db = NULL;
1.701 + HandleError err;
1.702 +
1.703 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.704 + != HandleError_None)
1.705 + {
1.706 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.707 + }
1.708 +
1.709 + if (!db->GetDriver()->IsThreadSafe())
1.710 + {
1.711 + return pContext->ThrowNativeError("Driver \"%s\" is not thread safe!", db->GetDriver()->GetIdentifier());
1.712 + }
1.713 +
1.714 + IPluginFunction *pf = pContext->GetFunctionById(params[2]);
1.715 + if (!pf)
1.716 + {
1.717 + return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
1.718 + }
1.719 +
1.720 + char *query;
1.721 + pContext->LocalToString(params[3], &query);
1.722 +
1.723 + cell_t data = params[4];
1.724 + PrioQueueLevel level = PrioQueue_Normal;
1.725 + if (params[5] == (cell_t)PrioQueue_High)
1.726 + {
1.727 + level = PrioQueue_High;
1.728 + } else if (params[5] == (cell_t)PrioQueue_Low) {
1.729 + level = PrioQueue_Low;
1.730 + }
1.731 +
1.732 + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
1.733 +
1.734 + TQueryOp *op = new TQueryOp(db, pf, query, data);
1.735 + if (pPlugin->GetProperty("DisallowDBThreads", NULL)
1.736 + || !g_DBMan.AddToThreadQueue(op, level))
1.737 + {
1.738 + /* Do everything right now */
1.739 + op->RunThreadPart();
1.740 + op->RunThinkPart();
1.741 + op->Destroy();
1.742 + }
1.743 +
1.744 + return 1;
1.745 +}
1.746 +
1.747 +static cell_t SQL_LockDatabase(IPluginContext *pContext, const cell_t *params)
1.748 +{
1.749 + IDatabase *db = NULL;
1.750 + HandleError err;
1.751 +
1.752 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.753 + != HandleError_None)
1.754 + {
1.755 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.756 + }
1.757 +
1.758 + db->LockForFullAtomicOperation();
1.759 +
1.760 + return 1;
1.761 +}
1.762 +
1.763 +static cell_t SQL_UnlockDatabase(IPluginContext *pContext, const cell_t *params)
1.764 +{
1.765 + IDatabase *db = NULL;
1.766 + HandleError err;
1.767 +
1.768 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.769 + != HandleError_None)
1.770 + {
1.771 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.772 + }
1.773 +
1.774 + db->UnlockFromFullAtomicOperation();
1.775 +
1.776 + return 1;
1.777 +}
1.778 +
1.779 +static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
1.780 +{
1.781 + IDatabase *db = NULL;
1.782 + HandleError err;
1.783 +
1.784 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1.785 + != HandleError_None)
1.786 + {
1.787 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1.788 + }
1.789 +
1.790 + char *query, *error;
1.791 + size_t maxlength = (size_t)params[4];
1.792 + pContext->LocalToString(params[2], &query);
1.793 + pContext->LocalToString(params[3], &error);
1.794 +
1.795 + IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
1.796 +
1.797 + if (!qr)
1.798 + {
1.799 + return BAD_HANDLE;
1.800 + }
1.801 +
1.802 + Handle_t hndl = g_HandleSys.CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
1.803 + if (hndl == BAD_HANDLE)
1.804 + {
1.805 + qr->Destroy();
1.806 + return BAD_HANDLE;
1.807 + }
1.808 +
1.809 + return hndl;
1.810 +}
1.811 +
1.812 +static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
1.813 +{
1.814 + IQuery *query;
1.815 + HandleError err;
1.816 +
1.817 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.818 + {
1.819 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.820 + }
1.821 +
1.822 + return query->FetchMoreResults() ? 1 : 0;
1.823 +}
1.824 +
1.825 +static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
1.826 +{
1.827 + IQuery *query;
1.828 + HandleError err;
1.829 +
1.830 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.831 + {
1.832 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.833 + }
1.834 +
1.835 + return query->GetResultSet() != NULL ? true : false;
1.836 +}
1.837 +
1.838 +static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
1.839 +{
1.840 + IQuery *query;
1.841 + HandleError err;
1.842 +
1.843 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.844 + {
1.845 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.846 + }
1.847 +
1.848 + IResultSet *rs = query->GetResultSet();
1.849 + if (!rs)
1.850 + {
1.851 + return 0;
1.852 + }
1.853 +
1.854 + return rs->GetRowCount();
1.855 +}
1.856 +
1.857 +static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
1.858 +{
1.859 + IQuery *query;
1.860 + HandleError err;
1.861 +
1.862 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.863 + {
1.864 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.865 + }
1.866 +
1.867 + IResultSet *rs = query->GetResultSet();
1.868 + if (!rs)
1.869 + {
1.870 + return 0;
1.871 + }
1.872 +
1.873 + return rs->GetFieldCount();
1.874 +}
1.875 +
1.876 +static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
1.877 +{
1.878 + IQuery *query;
1.879 + HandleError err;
1.880 +
1.881 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.882 + {
1.883 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.884 + }
1.885 +
1.886 + IResultSet *rs = query->GetResultSet();
1.887 + if (!rs)
1.888 + {
1.889 + return pContext->ThrowNativeError("No current result set");
1.890 + }
1.891 +
1.892 + unsigned int field = params[2];
1.893 +
1.894 + const char *fldname;
1.895 + if ((fldname = rs->FieldNumToName(field)) == NULL)
1.896 + {
1.897 + return pContext->ThrowNativeError("Invalid field index %d", field);
1.898 + }
1.899 +
1.900 + pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
1.901 +
1.902 + return 1;
1.903 +}
1.904 +
1.905 +static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
1.906 +{
1.907 + IQuery *query;
1.908 + HandleError err;
1.909 +
1.910 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.911 + {
1.912 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.913 + }
1.914 +
1.915 + IResultSet *rs = query->GetResultSet();
1.916 + if (!rs)
1.917 + {
1.918 + return pContext->ThrowNativeError("No current result set");
1.919 + }
1.920 +
1.921 + char *field;
1.922 + pContext->LocalToString(params[2], &field);
1.923 +
1.924 + cell_t *num;
1.925 + pContext->LocalToPhysAddr(params[3], &num);
1.926 +
1.927 + return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
1.928 +}
1.929 +
1.930 +static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
1.931 +{
1.932 + IQuery *query;
1.933 + HandleError err;
1.934 +
1.935 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.936 + {
1.937 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.938 + }
1.939 +
1.940 + IResultSet *rs = query->GetResultSet();
1.941 + if (!rs)
1.942 + {
1.943 + return pContext->ThrowNativeError("No current result set");
1.944 + }
1.945 +
1.946 + return (rs->FetchRow() != NULL) ? true : false;
1.947 +}
1.948 +
1.949 +static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
1.950 +{
1.951 + IQuery *query;
1.952 + HandleError err;
1.953 +
1.954 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.955 + {
1.956 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.957 + }
1.958 +
1.959 + IResultSet *rs = query->GetResultSet();
1.960 + if (!rs)
1.961 + {
1.962 + return pContext->ThrowNativeError("No current result set");
1.963 + }
1.964 +
1.965 + return rs->MoreRows() ? 1 : 0;
1.966 +}
1.967 +
1.968 +static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
1.969 +{
1.970 + IQuery *query;
1.971 + HandleError err;
1.972 +
1.973 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.974 + {
1.975 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.976 + }
1.977 +
1.978 + IResultSet *rs = query->GetResultSet();
1.979 + if (!rs)
1.980 + {
1.981 + return pContext->ThrowNativeError("No current result set");
1.982 + }
1.983 +
1.984 + return rs->Rewind() ? 1 : 0;
1.985 +}
1.986 +
1.987 +static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
1.988 +{
1.989 + IQuery *query;
1.990 + HandleError err;
1.991 +
1.992 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.993 + {
1.994 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.995 + }
1.996 +
1.997 + IResultSet *rs = query->GetResultSet();
1.998 + if (!rs)
1.999 + {
1.1000 + return pContext->ThrowNativeError("No current result set");
1.1001 + }
1.1002 +
1.1003 + IResultRow *row = rs->CurrentRow();
1.1004 + if (!row)
1.1005 + {
1.1006 + return pContext->ThrowNativeError("Current result set has no fetched rows");
1.1007 + }
1.1008 +
1.1009 + const char *str;
1.1010 + size_t length;
1.1011 + DBResult res = row->GetString(params[2], &str, &length);
1.1012 +
1.1013 + if (res == DBVal_Error)
1.1014 + {
1.1015 + return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
1.1016 + } else if (res == DBVal_TypeMismatch) {
1.1017 + return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
1.1018 + }
1.1019 +
1.1020 + pContext->StringToLocalUTF8(params[3], params[4], str, &length);
1.1021 +
1.1022 + cell_t *addr;
1.1023 + pContext->LocalToPhysAddr(params[5], &addr);
1.1024 + *addr = (cell_t)res;
1.1025 +
1.1026 + return (cell_t)length;
1.1027 +}
1.1028 +
1.1029 +static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
1.1030 +{
1.1031 + IQuery *query;
1.1032 + HandleError err;
1.1033 +
1.1034 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.1035 + {
1.1036 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.1037 + }
1.1038 +
1.1039 + IResultSet *rs = query->GetResultSet();
1.1040 + if (!rs)
1.1041 + {
1.1042 + return pContext->ThrowNativeError("No current result set");
1.1043 + }
1.1044 +
1.1045 + IResultRow *row = rs->CurrentRow();
1.1046 + if (!row)
1.1047 + {
1.1048 + return pContext->ThrowNativeError("Current result set has no fetched rows");
1.1049 + }
1.1050 +
1.1051 + float f;
1.1052 + DBResult res = row->GetFloat(params[2], &f);
1.1053 +
1.1054 + if (res == DBVal_Error)
1.1055 + {
1.1056 + return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
1.1057 + } else if (res == DBVal_TypeMismatch) {
1.1058 + return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
1.1059 + }
1.1060 +
1.1061 + cell_t *addr;
1.1062 + pContext->LocalToPhysAddr(params[3], &addr);
1.1063 + *addr = (cell_t)res;
1.1064 +
1.1065 + return sp_ftoc(f);
1.1066 +}
1.1067 +
1.1068 +static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
1.1069 +{
1.1070 + IQuery *query;
1.1071 + HandleError err;
1.1072 +
1.1073 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.1074 + {
1.1075 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.1076 + }
1.1077 +
1.1078 + IResultSet *rs = query->GetResultSet();
1.1079 + if (!rs)
1.1080 + {
1.1081 + return pContext->ThrowNativeError("No current result set");
1.1082 + }
1.1083 +
1.1084 + IResultRow *row = rs->CurrentRow();
1.1085 + if (!row)
1.1086 + {
1.1087 + return pContext->ThrowNativeError("Current result set has no fetched rows");
1.1088 + }
1.1089 +
1.1090 + int iv;
1.1091 + DBResult res = row->GetInt(params[2], &iv);
1.1092 +
1.1093 + if (res == DBVal_Error)
1.1094 + {
1.1095 + return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
1.1096 + } else if (res == DBVal_TypeMismatch) {
1.1097 + return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
1.1098 + }
1.1099 +
1.1100 + cell_t *addr;
1.1101 + pContext->LocalToPhysAddr(params[3], &addr);
1.1102 + *addr = (cell_t)res;
1.1103 +
1.1104 + return iv;
1.1105 +}
1.1106 +
1.1107 +static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
1.1108 +{
1.1109 + IQuery *query;
1.1110 + HandleError err;
1.1111 +
1.1112 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.1113 + {
1.1114 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.1115 + }
1.1116 +
1.1117 + IResultSet *rs = query->GetResultSet();
1.1118 + if (!rs)
1.1119 + {
1.1120 + return pContext->ThrowNativeError("No current result set");
1.1121 + }
1.1122 +
1.1123 + IResultRow *row = rs->CurrentRow();
1.1124 + if (!row)
1.1125 + {
1.1126 + return pContext->ThrowNativeError("Current result set has no fetched rows");
1.1127 + }
1.1128 +
1.1129 + if ((unsigned)params[2] >= rs->GetFieldCount())
1.1130 + {
1.1131 + return pContext->ThrowNativeError("Invalid field index %d", params[2]);
1.1132 + }
1.1133 +
1.1134 + return row->IsNull(params[2]) ? 1 : 0;
1.1135 +}
1.1136 +
1.1137 +static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
1.1138 +{
1.1139 + IQuery *query;
1.1140 + HandleError err;
1.1141 +
1.1142 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1.1143 + {
1.1144 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1.1145 + }
1.1146 +
1.1147 + IResultSet *rs = query->GetResultSet();
1.1148 + if (!rs)
1.1149 + {
1.1150 + return pContext->ThrowNativeError("No current result set");
1.1151 + }
1.1152 +
1.1153 + IResultRow *row = rs->CurrentRow();
1.1154 + if (!row)
1.1155 + {
1.1156 + return pContext->ThrowNativeError("Current result set has no fetched rows");
1.1157 + }
1.1158 +
1.1159 + if ((unsigned)params[2] >= rs->GetFieldCount())
1.1160 + {
1.1161 + return pContext->ThrowNativeError("Invalid field index %d", params[2]);
1.1162 + }
1.1163 +
1.1164 + return row->GetDataSize(params[2]);
1.1165 +}
1.1166 +
1.1167 +static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
1.1168 +{
1.1169 + IPreparedQuery *stmt;
1.1170 + HandleError err;
1.1171 +
1.1172 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1.1173 + {
1.1174 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1.1175 + }
1.1176 +
1.1177 + if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
1.1178 + {
1.1179 + return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
1.1180 + }
1.1181 +
1.1182 + return 1;
1.1183 +}
1.1184 +
1.1185 +static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
1.1186 +{
1.1187 + IPreparedQuery *stmt;
1.1188 + HandleError err;
1.1189 +
1.1190 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1.1191 + {
1.1192 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1.1193 + }
1.1194 +
1.1195 + if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
1.1196 + {
1.1197 + return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
1.1198 + }
1.1199 +
1.1200 + return 1;
1.1201 +}
1.1202 +
1.1203 +static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
1.1204 +{
1.1205 + IPreparedQuery *stmt;
1.1206 + HandleError err;
1.1207 +
1.1208 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1.1209 + {
1.1210 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1.1211 + }
1.1212 +
1.1213 + char *str;
1.1214 + pContext->LocalToString(params[3], &str);
1.1215 +
1.1216 + if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
1.1217 + {
1.1218 + return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
1.1219 + }
1.1220 +
1.1221 + return 1;
1.1222 +}
1.1223 +
1.1224 +static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
1.1225 +{
1.1226 + IPreparedQuery *stmt;
1.1227 + HandleError err;
1.1228 +
1.1229 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1.1230 + {
1.1231 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1.1232 + }
1.1233 +
1.1234 + return stmt->Execute() ? 1 : 0;
1.1235 +}
1.1236 +
1.1237 +static cell_t SQL_IsSameConnection(IPluginContext *pContext, const cell_t *params)
1.1238 +{
1.1239 + IDatabase *db1=NULL, *db2=NULL;
1.1240 + HandleError err;
1.1241 +
1.1242 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
1.1243 + != HandleError_None)
1.1244 + {
1.1245 + return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
1.1246 + }
1.1247 +
1.1248 + if ((err = g_DBMan.ReadHandle(params[2], DBHandle_Database, (void **)&db2))
1.1249 + != HandleError_None)
1.1250 + {
1.1251 + return pContext->ThrowNativeError("Invalid database Handle 2/%x (error: %d)", params[2], err);
1.1252 + }
1.1253 +
1.1254 + return (db1 == db2) ? true : false;
1.1255 +}
1.1256 +
1.1257 +static cell_t SQL_ReadDriver(IPluginContext *pContext, const cell_t *params)
1.1258 +{
1.1259 + IDatabase *db1=NULL;
1.1260 + HandleError err;
1.1261 +
1.1262 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
1.1263 + != HandleError_None)
1.1264 + {
1.1265 + return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
1.1266 + }
1.1267 +
1.1268 + IDBDriver *driver = db1->GetDriver();
1.1269 +
1.1270 + pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
1.1271 +
1.1272 + return driver->GetHandle();
1.1273 +}
1.1274 +
1.1275 +static cell_t SQL_CheckConfig(IPluginContext *pContext, const cell_t *params)
1.1276 +{
1.1277 + char *name;
1.1278 + pContext->LocalToString(params[1], &name);
1.1279 +
1.1280 + return (g_DBMan.FindDatabaseConf(name) != NULL) ? 1 : 0;
1.1281 +}
1.1282 +
1.1283 +REGISTER_NATIVES(dbNatives)
1.1284 +{
1.1285 + {"SQL_BindParamInt", SQL_BindParamInt},
1.1286 + {"SQL_BindParamFloat", SQL_BindParamFloat},
1.1287 + {"SQL_BindParamString", SQL_BindParamString},\
1.1288 + {"SQL_CheckConfig", SQL_CheckConfig},
1.1289 + {"SQL_Connect", SQL_Connect},
1.1290 + {"SQL_ConnectEx", SQL_ConnectEx},
1.1291 + {"SQL_EscapeString", SQL_QuoteString},
1.1292 + {"SQL_Execute", SQL_Execute},
1.1293 + {"SQL_FastQuery", SQL_FastQuery},
1.1294 + {"SQL_FetchFloat", SQL_FetchFloat},
1.1295 + {"SQL_FetchInt", SQL_FetchInt},
1.1296 + {"SQL_FetchMoreResults", SQL_FetchMoreResults},
1.1297 + {"SQL_FetchRow", SQL_FetchRow},
1.1298 + {"SQL_FetchSize", SQL_FetchSize},
1.1299 + {"SQL_FetchString", SQL_FetchString},
1.1300 + {"SQL_FieldNameToNum", SQL_FieldNameToNum},
1.1301 + {"SQL_FieldNumToName", SQL_FieldNumToName},
1.1302 + {"SQL_GetAffectedRows", SQL_GetAffectedRows},
1.1303 + {"SQL_GetDriver", SQL_GetDriver},
1.1304 + {"SQL_GetDriverIdent", SQL_GetDriverIdent},
1.1305 + {"SQL_GetDriverProduct", SQL_GetDriverProduct},
1.1306 + {"SQL_GetError", SQL_GetError},
1.1307 + {"SQL_GetFieldCount", SQL_GetFieldCount},
1.1308 + {"SQL_GetInsertId", SQL_GetInsertId},
1.1309 + {"SQL_GetRowCount", SQL_GetRowCount},
1.1310 + {"SQL_HasResultSet", SQL_HasResultSet},
1.1311 + {"SQL_IsFieldNull", SQL_IsFieldNull},
1.1312 + {"SQL_IsSameConnection", SQL_IsSameConnection},
1.1313 + {"SQL_LockDatabase", SQL_LockDatabase},
1.1314 + {"SQL_MoreRows", SQL_MoreRows},
1.1315 + {"SQL_PrepareQuery", SQL_PrepareQuery},
1.1316 + {"SQL_Query", SQL_Query},
1.1317 + {"SQL_QuoteString", SQL_QuoteString},
1.1318 + {"SQL_ReadDriver", SQL_ReadDriver},
1.1319 + {"SQL_Rewind", SQL_Rewind},
1.1320 + {"SQL_TConnect", SQL_TConnect},
1.1321 + {"SQL_TQuery", SQL_TQuery},
1.1322 + {"SQL_UnlockDatabase", SQL_UnlockDatabase},
1.1323 + {NULL, NULL},
1.1324 +};