Trigger build for hl2sdk-l4d changes.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "common_logic.h"
34 #include "ExtensionSys.h"
35 #include "stringutil.h"
36 #include "ISourceMod.h"
38 HandleType_t hStmtType;
40 HandleType_t hCombinedQueryType;
47 class DatabaseHelpers :
49 public IHandleTypeDispatch
52 virtual void OnSourceModAllInitialized()
57 handlesys->InitAccessDefaults(NULL, &acc);
58 acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
62 handlesys->InitAccessDefaults(&tacc, NULL);
63 tacc.ident = g_pCoreIdent;
65 hCombinedQueryType = handlesys->CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
66 hStmtType = handlesys->CreateType("IPreparedQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
69 virtual void OnSourceModShutdown()
71 handlesys->RemoveType(hStmtType, g_pCoreIdent);
72 handlesys->RemoveType(hCombinedQueryType, g_pCoreIdent);
75 virtual void OnHandleDestroy(HandleType_t type, void *object)
77 if (type == hCombinedQueryType)
79 CombinedQuery *combined = (CombinedQuery *)object;
80 combined->query->Destroy();
82 } else if (type == hStmtType) {
83 IPreparedQuery *query = (IPreparedQuery *)object;
87 } s_DatabaseNativeHelpers;
89 //is this safe for stmt handles? i think since it's single inheritance, it always will be.
90 inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
94 sec.pOwner = pContext->GetIdentity();
95 sec.pIdentity = g_pCoreIdent;
99 if ((ret = handlesys->ReadHandle(hndl, hStmtType, &sec, (void **)query)) != HandleError_None)
101 ret = handlesys->ReadHandle(hndl, hCombinedQueryType, &sec, (void **)&c);
102 if (ret == HandleError_None)
110 inline HandleError ReadQueryAndDbHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query, IDatabase **db)
114 sec.pOwner = pContext->GetIdentity();
115 sec.pIdentity = g_pCoreIdent;
117 HandleError ret = handlesys->ReadHandle(hndl, hCombinedQueryType, &sec, (void **)&c);
118 if (ret == HandleError_None)
126 inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
129 sec.pOwner = pContext->GetIdentity();
130 sec.pIdentity = g_pCoreIdent;
132 return handlesys->ReadHandle(hndl, hStmtType, &sec, (void **)query);
135 inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
138 if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
141 return ReadStmtHndl(hndl, pContext, query);
146 class TQueryOp : public IDBThreadOperation
149 TQueryOp(IDatabase *db, IPluginFunction *pf, const char *query, cell_t data) :
150 m_pDatabase(db), m_pFunction(pf), m_Query(query), m_Data(data),
151 me(scripts->FindPluginByContext(pf->GetParentContext()->GetContext())),
154 /* We always increase the reference count because this is potentially
155 * asynchronous. Otherwise the original handle could be closed while
156 * we're still latched onto it.
158 m_pDatabase->IncReferenceCount();
160 /* Now create our own Handle such that it can only be closed by us.
161 * We allow cloning just in case someone wants to hold onto it.
163 HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
165 handlesys->InitAccessDefaults(NULL, &access);
166 access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
167 m_MyHandle = handlesys->CreateHandleEx(g_DBMan.GetDatabaseType(),
180 /* Close our Handle if it's valid. */
181 if (m_MyHandle != BAD_HANDLE)
183 HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
184 handlesys->FreeHandle(m_MyHandle, &sec);
186 /* Otherwise, there is an open ref to the db */
187 m_pDatabase->Close();
190 IdentityToken_t *GetOwner()
192 return me->GetIdentity();
194 IDBDriver *GetDriver()
196 return m_pDatabase->GetDriver();
200 m_pDatabase->LockForFullAtomicOperation();
201 m_pQuery = m_pDatabase->DoQuery(m_Query.c_str());
204 g_pSM->Format(error, sizeof(error), "%s", m_pDatabase->GetError());
206 m_pDatabase->UnlockFromFullAtomicOperation();
208 void CancelThinkPart()
210 m_pFunction->PushCell(BAD_HANDLE);
211 m_pFunction->PushCell(BAD_HANDLE);
212 m_pFunction->PushString("Driver is unloading");
213 m_pFunction->PushCell(m_Data);
214 m_pFunction->Execute(NULL);
218 /* Create a Handle for our query */
219 HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
221 handlesys->InitAccessDefaults(NULL, &access);
222 access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
224 Handle_t qh = BAD_HANDLE;
228 CombinedQuery *c = new CombinedQuery;
232 qh = handlesys->CreateHandle(hCombinedQueryType, c, me->GetIdentity(), g_pCoreIdent, NULL);
233 if (qh != BAD_HANDLE)
237 g_pSM->Format(error, sizeof(error), "Could not alloc handle");
242 m_pFunction->PushCell(m_MyHandle);
243 m_pFunction->PushCell(qh);
244 m_pFunction->PushString(qh == BAD_HANDLE ? error : "");
245 m_pFunction->PushCell(m_Data);
246 m_pFunction->Execute(NULL);
248 if (qh != BAD_HANDLE)
250 handlesys->FreeHandle(qh, &sec);
258 IDatabase *m_pDatabase;
259 IPluginFunction *m_pFunction;
268 class TConnectOp : public IDBThreadOperation
271 TConnectOp(IPluginFunction *func, IDBDriver *driver, const char *_dbname, cell_t data)
278 strncopy(dbname, _dbname, sizeof(dbname));
279 me = scripts->FindPluginByContext(m_pFunction->GetParentContext()->GetContext());
281 IdentityToken_t *GetOwner()
283 return me->GetIdentity();
285 IDBDriver *GetDriver()
291 g_DBMan.LockConfig();
292 const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(dbname);
295 g_pSM->Format(error, sizeof(error), "Could not find database config \"%s\"", dbname);
297 m_pDatabase = m_pDriver->Connect(pInfo, false, error, sizeof(error));
299 g_DBMan.UnlockConfig();
301 void CancelThinkPart()
305 m_pDatabase->Close();
307 m_pFunction->PushCell(BAD_HANDLE);
308 m_pFunction->PushCell(BAD_HANDLE);
309 m_pFunction->PushString("Driver is unloading");
310 m_pFunction->PushCell(m_Data);
311 m_pFunction->Execute(NULL);
315 Handle_t hndl = BAD_HANDLE;
319 if ((hndl = g_DBMan.CreateHandle(DBHandle_Database, m_pDatabase, me->GetIdentity()))
322 m_pDatabase->Close();
323 g_pSM->Format(error, sizeof(error), "Unable to allocate Handle");
327 m_pFunction->PushCell(m_pDriver->GetHandle());
328 m_pFunction->PushCell(hndl);
329 m_pFunction->PushString(hndl == BAD_HANDLE ? error : "");
330 m_pFunction->PushCell(m_Data);
331 m_pFunction->Execute(NULL);
339 IPluginFunction *m_pFunction;
340 IDBDriver *m_pDriver;
341 IDatabase *m_pDatabase;
347 static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
351 size_t maxlength = (size_t)params[4];
352 bool persistent = params[2] ? true : false;
353 pContext->LocalToString(params[1], &conf);
354 pContext->LocalToString(params[3], &err);
358 if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
363 Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
370 /* HACK! Add us to the dependency list */
371 IExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
374 g_Extensions.BindChildPlugin(pExt, scripts->FindPluginByContext(pContext->GetContext()));
380 static cell_t SQL_TConnect(IPluginContext *pContext, const cell_t *params)
382 IPluginFunction *pf = pContext->GetFunctionById(params[1]);
385 return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
389 pContext->LocalToString(params[2], &conf);
391 IDBDriver *driver = NULL;
392 const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(conf);
396 if (pInfo->driver[0] == '\0')
398 driver = g_DBMan.GetDefaultDriver();
400 driver = g_DBMan.FindOrLoadDriver(pInfo->driver);
406 "Could not find driver \"%s\"",
407 pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName() : pInfo->driver);
408 } else if (!driver->IsThreadSafe()) {
411 "Driver \"%s\" is not thread safe!",
412 driver->GetIdentifier());
415 g_pSM->Format(error, sizeof(error), "Could not find database conf \"%s\"", conf);
418 if (!pInfo || !driver)
420 pf->PushCell(BAD_HANDLE);
421 pf->PushCell(BAD_HANDLE);
422 pf->PushString(error);
428 /* HACK! Add us to the dependency list */
429 IExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
432 g_Extensions.BindChildPlugin(pExt, scripts->FindPluginByContext(pContext->GetContext()));
435 /* Finally, add to the thread if we can */
436 TConnectOp *op = new TConnectOp(pf, driver, conf, params[3]);
437 IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
438 if (pPlugin->GetProperty("DisallowDBThreads", NULL)
439 || !g_DBMan.AddToThreadQueue(op, PrioQueue_High))
441 /* Do everything right now */
450 static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
453 if (params[1] == BAD_HANDLE)
455 if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
457 return pContext->ThrowNativeError("Could not find any default driver");
461 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
464 return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
468 char *host, *user, *pass, *database, *error;
469 size_t maxlength = (size_t)params[7];
470 bool persistent = params[8] ? true : false;
471 unsigned int port = params[9];
472 unsigned int maxTimeout = params[10];
473 pContext->LocalToString(params[2], &host);
474 pContext->LocalToString(params[3], &user);
475 pContext->LocalToString(params[4], &pass);
476 pContext->LocalToString(params[5], &database);
477 pContext->LocalToString(params[6], &error);
480 info.database = database;
481 info.driver = driver->GetIdentifier();
483 info.maxTimeout = maxTimeout;
488 IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
492 Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
499 /* HACK! Add us to the dependency list */
500 IExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
503 g_Extensions.BindChildPlugin(pExt, scripts->FindPluginByContext(pContext->GetContext()));
512 static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
515 if (params[1] == BAD_HANDLE)
517 if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
519 return pContext->ThrowNativeError("Could not find any default driver");
523 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
526 return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
530 pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
535 static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
538 pContext->LocalToString(params[1], &name);
540 IDBDriver *driver = NULL;
543 driver = g_DBMan.GetDefaultDriver();
545 driver = g_DBMan.FindOrLoadDriver(name);
548 return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
551 static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
554 if (params[1] == BAD_HANDLE)
556 if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
558 return pContext->ThrowNativeError("Could not find any default driver");
562 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
565 return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
569 pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
574 static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
576 IDatabase *db = NULL;
577 IPreparedQuery *stmt = NULL;
578 IQuery *query = NULL;
581 if (((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
582 && ((err = ReadQueryAndDbHndl(params[1], pContext, &query, &db)) != HandleError_None))
584 return pContext->ThrowNativeError("Invalid statement, db, or query Handle %x (error: %d)", params[1], err);
590 return stmt->GetAffectedRows();
594 return db->GetAffectedRowsForQuery(query);
598 return db->GetAffectedRows();
601 return pContext->ThrowNativeError("Unknown error reading db/stmt/query handles");
604 static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
606 IDatabase *db = NULL;
607 IQuery *query = NULL;
608 IPreparedQuery *stmt = NULL;
611 if (((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
612 && ((err = ReadQueryAndDbHndl(params[1], pContext, &query, &db)) != HandleError_None))
614 return pContext->ThrowNativeError("Invalid statement, db, or query Handle %x (error: %d)", params[1], err);
619 return db->GetInsertIDForQuery(query);
623 return db->GetInsertID();
627 return stmt->GetInsertID();
630 return pContext->ThrowNativeError("Unknown error reading db/stmt/query handles");
633 static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
635 IDatabase *db = NULL;
636 IPreparedQuery *stmt = NULL;
639 if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
641 return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
644 const char *error = "";
647 error = db->GetError();
649 error = stmt->GetError();
652 if (error[0] == '\0')
657 pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
662 static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
664 IDatabase *db = NULL;
667 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
670 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
673 char *input, *output;
674 size_t maxlength = (size_t)params[4];
675 pContext->LocalToString(params[2], &input);
676 pContext->LocalToString(params[3], &output);
679 bool s = db->QuoteString(input, output, maxlength, &written);
682 pContext->LocalToPhysAddr(params[5], &addr);
683 *addr = (cell_t)written;
688 static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
690 IDatabase *db = NULL;
693 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
696 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
700 pContext->LocalToString(params[2], &query);
702 if (params[0] >= 3 && params[3] != -1)
704 return db->DoSimpleQueryEx(query, params[3]) ? 1 : 0;
707 return db->DoSimpleQuery(query) ? 1 : 0;
710 static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
712 IDatabase *db = NULL;
715 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
718 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
722 pContext->LocalToString(params[2], &query);
726 if (params[0] >= 3 && params[3] != -1)
728 qr = db->DoQueryEx(query, params[3]);
732 qr = db->DoQuery(query);
740 CombinedQuery *c = new CombinedQuery;
743 Handle_t hndl = handlesys->CreateHandle(hCombinedQueryType, c, pContext->GetIdentity(), g_pCoreIdent, NULL);
744 if (hndl == BAD_HANDLE)
754 static cell_t SQL_TQuery(IPluginContext *pContext, const cell_t *params)
756 IDatabase *db = NULL;
759 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
762 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
765 if (!db->GetDriver()->IsThreadSafe())
767 return pContext->ThrowNativeError("Driver \"%s\" is not thread safe!", db->GetDriver()->GetIdentifier());
770 IPluginFunction *pf = pContext->GetFunctionById(params[2]);
773 return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
777 pContext->LocalToString(params[3], &query);
779 cell_t data = params[4];
780 PrioQueueLevel level = PrioQueue_Normal;
781 if (params[5] == (cell_t)PrioQueue_High)
783 level = PrioQueue_High;
784 } else if (params[5] == (cell_t)PrioQueue_Low) {
785 level = PrioQueue_Low;
788 IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
790 TQueryOp *op = new TQueryOp(db, pf, query, data);
791 if (pPlugin->GetProperty("DisallowDBThreads", NULL)
792 || !g_DBMan.AddToThreadQueue(op, level))
794 /* Do everything right now */
803 static cell_t SQL_LockDatabase(IPluginContext *pContext, const cell_t *params)
805 IDatabase *db = NULL;
808 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
811 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
814 db->LockForFullAtomicOperation();
819 static cell_t SQL_UnlockDatabase(IPluginContext *pContext, const cell_t *params)
821 IDatabase *db = NULL;
824 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
827 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
830 db->UnlockFromFullAtomicOperation();
835 static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
837 IDatabase *db = NULL;
840 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
843 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
847 size_t maxlength = (size_t)params[4];
848 pContext->LocalToString(params[2], &query);
849 pContext->LocalToString(params[3], &error);
851 IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
858 Handle_t hndl = handlesys->CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
859 if (hndl == BAD_HANDLE)
868 static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
873 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
875 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
878 return query->FetchMoreResults() ? 1 : 0;
881 static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
886 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
888 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
891 return query->GetResultSet() != NULL ? true : false;
894 static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
899 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
901 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
904 IResultSet *rs = query->GetResultSet();
910 return rs->GetRowCount();
913 static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
918 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
920 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
923 IResultSet *rs = query->GetResultSet();
929 return rs->GetFieldCount();
932 static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
937 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
939 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
942 IResultSet *rs = query->GetResultSet();
945 return pContext->ThrowNativeError("No current result set");
948 unsigned int field = params[2];
951 if ((fldname = rs->FieldNumToName(field)) == NULL)
953 return pContext->ThrowNativeError("Invalid field index %d", field);
956 pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
961 static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
966 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
968 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
971 IResultSet *rs = query->GetResultSet();
974 return pContext->ThrowNativeError("No current result set");
978 pContext->LocalToString(params[2], &field);
981 pContext->LocalToPhysAddr(params[3], &num);
983 return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
986 static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
991 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
993 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
996 IResultSet *rs = query->GetResultSet();
999 return pContext->ThrowNativeError("No current result set");
1002 return (rs->FetchRow() != NULL) ? true : false;
1005 static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
1010 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1012 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1015 IResultSet *rs = query->GetResultSet();
1018 return pContext->ThrowNativeError("No current result set");
1021 return rs->MoreRows() ? 1 : 0;
1024 static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
1029 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1031 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1034 IResultSet *rs = query->GetResultSet();
1037 return pContext->ThrowNativeError("No current result set");
1040 return rs->Rewind() ? 1 : 0;
1043 static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
1048 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1050 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1053 IResultSet *rs = query->GetResultSet();
1056 return pContext->ThrowNativeError("No current result set");
1059 IResultRow *row = rs->CurrentRow();
1062 return pContext->ThrowNativeError("Current result set has no fetched rows");
1067 DBResult res = row->GetString(params[2], &str, &length);
1069 if (res == DBVal_Error)
1071 return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
1072 } else if (res == DBVal_TypeMismatch) {
1073 return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
1076 pContext->StringToLocalUTF8(params[3], params[4], str, &length);
1079 pContext->LocalToPhysAddr(params[5], &addr);
1080 *addr = (cell_t)res;
1082 return (cell_t)length;
1085 static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
1090 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1092 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1095 IResultSet *rs = query->GetResultSet();
1098 return pContext->ThrowNativeError("No current result set");
1101 IResultRow *row = rs->CurrentRow();
1104 return pContext->ThrowNativeError("Current result set has no fetched rows");
1108 DBResult res = row->GetFloat(params[2], &f);
1110 if (res == DBVal_Error)
1112 return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
1113 } else if (res == DBVal_TypeMismatch) {
1114 return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
1118 pContext->LocalToPhysAddr(params[3], &addr);
1119 *addr = (cell_t)res;
1124 static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
1129 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1131 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1134 IResultSet *rs = query->GetResultSet();
1137 return pContext->ThrowNativeError("No current result set");
1140 IResultRow *row = rs->CurrentRow();
1143 return pContext->ThrowNativeError("Current result set has no fetched rows");
1147 DBResult res = row->GetInt(params[2], &iv);
1149 if (res == DBVal_Error)
1151 return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
1152 } else if (res == DBVal_TypeMismatch) {
1153 return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
1157 pContext->LocalToPhysAddr(params[3], &addr);
1158 *addr = (cell_t)res;
1163 static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
1168 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1170 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1173 IResultSet *rs = query->GetResultSet();
1176 return pContext->ThrowNativeError("No current result set");
1179 IResultRow *row = rs->CurrentRow();
1182 return pContext->ThrowNativeError("Current result set has no fetched rows");
1185 if ((unsigned)params[2] >= rs->GetFieldCount())
1187 return pContext->ThrowNativeError("Invalid field index %d", params[2]);
1190 return row->IsNull(params[2]) ? 1 : 0;
1193 static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
1198 if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
1200 return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
1203 IResultSet *rs = query->GetResultSet();
1206 return pContext->ThrowNativeError("No current result set");
1209 IResultRow *row = rs->CurrentRow();
1212 return pContext->ThrowNativeError("Current result set has no fetched rows");
1215 if ((unsigned)params[2] >= rs->GetFieldCount())
1217 return pContext->ThrowNativeError("Invalid field index %d", params[2]);
1220 return row->GetDataSize(params[2]);
1223 static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
1225 IPreparedQuery *stmt;
1228 if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1230 return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1233 if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
1235 return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
1241 static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
1243 IPreparedQuery *stmt;
1246 if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1248 return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1251 if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
1253 return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
1259 static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
1261 IPreparedQuery *stmt;
1264 if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1266 return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1270 pContext->LocalToString(params[3], &str);
1272 if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
1274 return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
1280 static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
1282 IPreparedQuery *stmt;
1285 if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
1287 return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
1290 return stmt->Execute() ? 1 : 0;
1293 static cell_t SQL_IsSameConnection(IPluginContext *pContext, const cell_t *params)
1295 IDatabase *db1=NULL, *db2=NULL;
1298 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
1299 != HandleError_None)
1301 return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
1304 if ((err = g_DBMan.ReadHandle(params[2], DBHandle_Database, (void **)&db2))
1305 != HandleError_None)
1307 return pContext->ThrowNativeError("Invalid database Handle 2/%x (error: %d)", params[2], err);
1310 return (db1 == db2) ? true : false;
1313 static cell_t SQL_ReadDriver(IPluginContext *pContext, const cell_t *params)
1315 IDatabase *db1=NULL;
1318 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
1319 != HandleError_None)
1321 return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
1324 IDBDriver *driver = db1->GetDriver();
1326 pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
1328 return driver->GetHandle();
1331 static cell_t SQL_CheckConfig(IPluginContext *pContext, const cell_t *params)
1334 pContext->LocalToString(params[1], &name);
1336 return (g_DBMan.FindDatabaseConf(name) != NULL) ? 1 : 0;
1339 static cell_t SQL_ConnectCustom(IPluginContext *pContext, const cell_t *params)
1344 kv = g_pSM->ReadKeyValuesHandle(params[1], &err, false);
1347 return pContext->ThrowNativeError("Invalid KeyValues handle %x (error: %d)",
1352 DatabaseInfo info = smcore.GetDBInfoFromKeyValues(kv);
1355 if (info.driver[0] == '\0' || strcmp(info.driver, "default") == 0)
1357 driver = g_DBMan.GetDefaultDriver();
1361 driver = g_DBMan.FindOrLoadDriver(info.driver);
1368 g_pSM->Format(buffer, sizeof(buffer), "Could not find driver \"%s\"", info.driver);
1369 pContext->StringToLocalUTF8(params[2], params[3], buffer, NULL);
1377 pContext->LocalToString(params[2], &buffer);
1379 db = driver->Connect(&info, params[4] ? true : false, buffer, params[3]);
1385 Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
1389 return pContext->ThrowNativeError("Out of handles!");
1392 /* HACK! Add us to the dependency list */
1393 IExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
1396 g_Extensions.BindChildPlugin(pExt, scripts->FindPluginByContext(pContext->GetContext()));
1402 static cell_t SQL_SetCharset(IPluginContext *pContext, const cell_t *params)
1404 IDatabase *db = NULL;
1407 if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
1408 != HandleError_None)
1410 return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
1414 pContext->LocalToString(params[2], &characterset);
1416 return db->SetCharacterSet(characterset);
1419 REGISTER_NATIVES(dbNatives)
1421 {"SQL_BindParamInt", SQL_BindParamInt},
1422 {"SQL_BindParamFloat", SQL_BindParamFloat},
1423 {"SQL_BindParamString", SQL_BindParamString},\
1424 {"SQL_CheckConfig", SQL_CheckConfig},
1425 {"SQL_Connect", SQL_Connect},
1426 {"SQL_ConnectEx", SQL_ConnectEx},
1427 {"SQL_EscapeString", SQL_QuoteString},
1428 {"SQL_Execute", SQL_Execute},
1429 {"SQL_FastQuery", SQL_FastQuery},
1430 {"SQL_FetchFloat", SQL_FetchFloat},
1431 {"SQL_FetchInt", SQL_FetchInt},
1432 {"SQL_FetchMoreResults", SQL_FetchMoreResults},
1433 {"SQL_FetchRow", SQL_FetchRow},
1434 {"SQL_FetchSize", SQL_FetchSize},
1435 {"SQL_FetchString", SQL_FetchString},
1436 {"SQL_FieldNameToNum", SQL_FieldNameToNum},
1437 {"SQL_FieldNumToName", SQL_FieldNumToName},
1438 {"SQL_GetAffectedRows", SQL_GetAffectedRows},
1439 {"SQL_GetDriver", SQL_GetDriver},
1440 {"SQL_GetDriverIdent", SQL_GetDriverIdent},
1441 {"SQL_GetDriverProduct", SQL_GetDriverProduct},
1442 {"SQL_GetError", SQL_GetError},
1443 {"SQL_GetFieldCount", SQL_GetFieldCount},
1444 {"SQL_GetInsertId", SQL_GetInsertId},
1445 {"SQL_GetRowCount", SQL_GetRowCount},
1446 {"SQL_HasResultSet", SQL_HasResultSet},
1447 {"SQL_IsFieldNull", SQL_IsFieldNull},
1448 {"SQL_IsSameConnection", SQL_IsSameConnection},
1449 {"SQL_LockDatabase", SQL_LockDatabase},
1450 {"SQL_MoreRows", SQL_MoreRows},
1451 {"SQL_PrepareQuery", SQL_PrepareQuery},
1452 {"SQL_Query", SQL_Query},
1453 {"SQL_QuoteString", SQL_QuoteString},
1454 {"SQL_ReadDriver", SQL_ReadDriver},
1455 {"SQL_Rewind", SQL_Rewind},
1456 {"SQL_TConnect", SQL_TConnect},
1457 {"SQL_TQuery", SQL_TQuery},
1458 {"SQL_UnlockDatabase", SQL_UnlockDatabase},
1459 {"SQL_ConnectCustom", SQL_ConnectCustom},
1460 {"SQL_SetCharset", SQL_SetCharset},