core/smn_database.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2086 debb2ab2c782
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include "sm_globals.h"
ds@1952
    33
#include "HandleSys.h"
ds@1952
    34
#include "Database.h"
ds@1952
    35
#include "ExtensionSys.h"
ds@1952
    36
#include "PluginSys.h"
ds@1952
    37
#include "sm_stringutil.h"
ds@1952
    38
ds@1952
    39
HandleType_t hQueryType;
ds@1952
    40
HandleType_t hStmtType;
ds@1952
    41
ds@1952
    42
class DatabaseHelpers : 
ds@1952
    43
	public SMGlobalClass,
ds@1952
    44
	public IHandleTypeDispatch
ds@1952
    45
{
ds@1952
    46
public:
ds@1952
    47
	virtual void OnSourceModAllInitialized()
ds@1952
    48
	{
ds@1952
    49
		HandleAccess acc;
ds@1952
    50
ds@1952
    51
		/* Disable cloning */
ds@1952
    52
		g_HandleSys.InitAccessDefaults(NULL, &acc);
ds@1952
    53
		acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
ds@1952
    54
ds@1952
    55
		TypeAccess tacc;
ds@1952
    56
ds@1952
    57
		g_HandleSys.InitAccessDefaults(&tacc, NULL);
ds@1952
    58
		tacc.ident = g_pCoreIdent;
ds@1952
    59
ds@1952
    60
		hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
ds@1952
    61
		hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, g_pCoreIdent, NULL);
ds@1952
    62
	}
ds@1952
    63
ds@1952
    64
	virtual void OnSourceModShutdown()
ds@1952
    65
	{
ds@1952
    66
		g_HandleSys.RemoveType(hStmtType, g_pCoreIdent);
ds@1952
    67
		g_HandleSys.RemoveType(hQueryType, g_pCoreIdent);
ds@1952
    68
	}
ds@1952
    69
ds@1952
    70
	virtual void OnHandleDestroy(HandleType_t type, void *object)
ds@1952
    71
	{
ds@1952
    72
		if (type == hQueryType)
ds@1952
    73
		{
ds@1952
    74
			IQuery *query = (IQuery *)object;
ds@1952
    75
			query->Destroy();
ds@1952
    76
		} else if (type == hStmtType) {
ds@1952
    77
			IPreparedQuery *query = (IPreparedQuery *)object;
ds@1952
    78
			query->Destroy();
ds@1952
    79
		}
ds@1952
    80
	}
ds@1952
    81
} s_DatabaseNativeHelpers;
ds@1952
    82
ds@1952
    83
//is this safe for stmt handles? i think since it's single inheritance, it always will be.
ds@1952
    84
inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
ds@1952
    85
{
ds@1952
    86
	HandleSecurity sec;
ds@1952
    87
	sec.pOwner = pContext->GetIdentity();
ds@1952
    88
	sec.pIdentity = g_pCoreIdent;
ds@1952
    89
ds@1952
    90
	return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query);
ds@1952
    91
}
ds@1952
    92
ds@1952
    93
inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
ds@1952
    94
{
ds@1952
    95
	HandleSecurity sec;
ds@1952
    96
	sec.pOwner = pContext->GetIdentity();
ds@1952
    97
	sec.pIdentity = g_pCoreIdent;
ds@1952
    98
ds@1952
    99
	return g_HandleSys.ReadHandle(hndl, hStmtType, &sec, (void **)query);
ds@1952
   100
}
ds@1952
   101
ds@1952
   102
inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
ds@1952
   103
{
ds@1952
   104
	HandleError err;
ds@1952
   105
	if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
ds@1952
   106
	{
ds@1952
   107
		*db = NULL;
ds@1952
   108
		return ReadStmtHndl(hndl, pContext, query);
ds@1952
   109
	}
ds@1952
   110
	return err;
ds@1952
   111
}
ds@1952
   112
ds@1952
   113
class TQueryOp : public IDBThreadOperation
ds@1952
   114
{
ds@1952
   115
public:
ds@1952
   116
	TQueryOp(IDatabase *db, IPluginFunction *pf, const char *query, cell_t data) : 
ds@1952
   117
	  m_pDatabase(db), m_pFunction(pf), m_Query(query), m_Data(data),
ds@1952
   118
	  me(g_PluginSys.GetPluginByCtx(pf->GetParentContext()->GetContext())),
ds@1952
   119
	  m_pQuery(NULL)
ds@1952
   120
	{
ds@1952
   121
		/* We always increase the reference count because this is potentially
ds@1952
   122
		 * asynchronous.  Otherwise the original handle could be closed while 
ds@1952
   123
		 * we're still latched onto it.
ds@1952
   124
		 */
ds@1952
   125
		m_pDatabase->IncReferenceCount();
ds@1952
   126
ds@1952
   127
		/* Now create our own Handle such that it can only be closed by us.
ds@1952
   128
		 * We allow cloning just in case someone wants to hold onto it.
ds@1952
   129
		 */
ds@1952
   130
		HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
ds@1952
   131
		HandleAccess access;
ds@1952
   132
		g_HandleSys.InitAccessDefaults(NULL, &access);
ds@1952
   133
		access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
ds@1952
   134
		m_MyHandle = g_HandleSys.CreateHandleEx(g_DBMan.GetDatabaseType(),
ds@1952
   135
			db,
ds@1952
   136
			&sec,
ds@1952
   137
			&access,
ds@1952
   138
			NULL);
ds@1952
   139
	}
ds@1952
   140
	~TQueryOp()
ds@1952
   141
	{
ds@1952
   142
		if (m_pQuery)
ds@1952
   143
		{
ds@1952
   144
			m_pQuery->Destroy();
ds@1952
   145
		}
ds@1952
   146
ds@1952
   147
		/* Close our Handle if it's valid. */
ds@1952
   148
		if (m_MyHandle != BAD_HANDLE)
ds@1952
   149
		{
ds@1952
   150
			HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
ds@1952
   151
			g_HandleSys.FreeHandle(m_MyHandle, &sec);
ds@1952
   152
		} else {
ds@1952
   153
			/* Otherwise, there is an open ref to the db */
ds@1952
   154
			m_pDatabase->Close();
ds@1952
   155
		}
ds@1952
   156
	}
ds@1952
   157
	IdentityToken_t *GetOwner()
ds@1952
   158
	{
ds@1952
   159
		return me->GetIdentity();
ds@1952
   160
	}
ds@1952
   161
	IDBDriver *GetDriver()
ds@1952
   162
	{
ds@1952
   163
		return m_pDatabase->GetDriver();
ds@1952
   164
	}
ds@1952
   165
	void RunThreadPart()
ds@1952
   166
	{
ds@1952
   167
		m_pDatabase->LockForFullAtomicOperation();
ds@1952
   168
		m_pQuery = m_pDatabase->DoQuery(m_Query.c_str());
ds@1952
   169
		if (!m_pQuery)
ds@1952
   170
		{
ds@1952
   171
			UTIL_Format(error, sizeof(error), "%s", m_pDatabase->GetError());
ds@1952
   172
		}
ds@1952
   173
		m_pDatabase->UnlockFromFullAtomicOperation();
ds@1952
   174
	}
ds@1952
   175
	void CancelThinkPart()
ds@1952
   176
	{
ds@1952
   177
		m_pFunction->PushCell(BAD_HANDLE);
ds@1952
   178
		m_pFunction->PushCell(BAD_HANDLE);
ds@1952
   179
		m_pFunction->PushString("Driver is unloading");
ds@1952
   180
		m_pFunction->PushCell(m_Data);
ds@1952
   181
		m_pFunction->Execute(NULL);
ds@1952
   182
	}
ds@1952
   183
	void RunThinkPart()
ds@1952
   184
	{
ds@1952
   185
		/* Create a Handle for our query */
ds@1952
   186
		HandleSecurity sec(me->GetIdentity(), g_pCoreIdent);
ds@1952
   187
		HandleAccess access;
ds@1952
   188
		g_HandleSys.InitAccessDefaults(NULL, &access);
ds@1952
   189
		access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
ds@1952
   190
ds@1952
   191
		Handle_t qh = BAD_HANDLE;
ds@1952
   192
		
ds@1952
   193
		if (m_pQuery)
ds@1952
   194
		{
ds@1952
   195
			qh = g_HandleSys.CreateHandle(hQueryType, m_pQuery, me->GetIdentity(), g_pCoreIdent, NULL);
ds@1952
   196
			if (qh != BAD_HANDLE)
ds@1952
   197
			{
ds@1952
   198
				m_pQuery = NULL;
ds@1952
   199
			} else {
ds@1952
   200
				UTIL_Format(error, sizeof(error), "Could not alloc handle");
ds@1952
   201
			}
ds@1952
   202
		}
ds@1952
   203
ds@1952
   204
		m_pFunction->PushCell(m_MyHandle);
ds@1952
   205
		m_pFunction->PushCell(qh);
ds@1952
   206
		m_pFunction->PushString(qh == BAD_HANDLE ? error : "");
ds@1952
   207
		m_pFunction->PushCell(m_Data);
ds@1952
   208
		m_pFunction->Execute(NULL);
ds@1952
   209
ds@1952
   210
		if (qh != BAD_HANDLE)
ds@1952
   211
		{
ds@1952
   212
			g_HandleSys.FreeHandle(qh, &sec);
ds@1952
   213
		}
ds@1952
   214
	}
ds@1952
   215
	void Destroy()
ds@1952
   216
	{
ds@1952
   217
		delete this;
ds@1952
   218
	}
ds@1952
   219
private:
ds@1952
   220
	IDatabase *m_pDatabase;
ds@1952
   221
	IPluginFunction *m_pFunction;
ds@1952
   222
	String m_Query;
ds@1952
   223
	cell_t m_Data;
ds@1952
   224
	CPlugin *me;
ds@1952
   225
	IQuery *m_pQuery;
ds@1952
   226
	char error[255];
ds@1952
   227
	Handle_t m_MyHandle;
ds@1952
   228
};
ds@1952
   229
ds@1952
   230
class TConnectOp : public IDBThreadOperation
ds@1952
   231
{
ds@1952
   232
public:
ds@1952
   233
	TConnectOp(IPluginFunction *func, IDBDriver *driver, const char *_dbname, cell_t data)
ds@1952
   234
	{
ds@1952
   235
		m_pFunction = func;
ds@1952
   236
		m_pDriver = driver;
ds@1952
   237
		m_pDatabase = NULL;
ds@1952
   238
		m_Data = data;
ds@1952
   239
		error[0] = '\0';
ds@1952
   240
		strncopy(dbname, _dbname, sizeof(dbname));
ds@1952
   241
		me = g_PluginSys.GetPluginByCtx(m_pFunction->GetParentContext()->GetContext());
ds@1952
   242
	}
ds@1952
   243
	IdentityToken_t *GetOwner()
ds@1952
   244
	{
ds@1952
   245
		return me->GetIdentity();
ds@1952
   246
	}
ds@1952
   247
	IDBDriver *GetDriver()
ds@1952
   248
	{
ds@1952
   249
		return m_pDriver;
ds@1952
   250
	}
ds@1952
   251
	void RunThreadPart()
ds@1952
   252
	{
ds@1952
   253
		g_DBMan.LockConfig();
ds@1952
   254
		const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(dbname);
ds@1952
   255
		if (!pInfo)
ds@1952
   256
		{
ds@1952
   257
			UTIL_Format(error, sizeof(error), "Could not find database config \"%s\"", dbname);
ds@1952
   258
		} else {
ds@1952
   259
			m_pDatabase = m_pDriver->Connect(pInfo, false, error, sizeof(error));
ds@1952
   260
		}
ds@1952
   261
		g_DBMan.UnlockConfig();
ds@1952
   262
	}
ds@1952
   263
	void CancelThinkPart()
ds@1952
   264
	{
ds@1952
   265
		if (m_pDatabase)
ds@1952
   266
		{
ds@1952
   267
			m_pDatabase->Close();
ds@1952
   268
		}
ds@1952
   269
		m_pFunction->PushCell(BAD_HANDLE);
ds@1952
   270
		m_pFunction->PushCell(BAD_HANDLE);
ds@1952
   271
		m_pFunction->PushString("Driver is unloading");
ds@1952
   272
		m_pFunction->PushCell(m_Data);
ds@1952
   273
		m_pFunction->Execute(NULL);
ds@1952
   274
	}
ds@1952
   275
	void RunThinkPart()
ds@1952
   276
	{
ds@1952
   277
		Handle_t hndl = BAD_HANDLE;
ds@1952
   278
		
ds@1952
   279
		if (m_pDatabase)
ds@1952
   280
		{
ds@1952
   281
			if ((hndl = g_DBMan.CreateHandle(DBHandle_Database, m_pDatabase, me->GetIdentity()))
ds@1952
   282
				== BAD_HANDLE)
ds@1952
   283
			{
ds@1952
   284
				m_pDatabase->Close();
ds@1952
   285
				UTIL_Format(error, sizeof(error), "Unable to allocate Handle");
ds@1952
   286
			}
ds@1952
   287
		}
ds@1952
   288
ds@1952
   289
		m_pFunction->PushCell(m_pDriver->GetHandle());
ds@1952
   290
		m_pFunction->PushCell(hndl);
ds@1952
   291
		m_pFunction->PushString(hndl == BAD_HANDLE ? error : "");
ds@1952
   292
		m_pFunction->PushCell(m_Data);
ds@1952
   293
		m_pFunction->Execute(NULL);
ds@1952
   294
	}
ds@1952
   295
	void Destroy()
ds@1952
   296
	{
ds@1952
   297
		delete this;
ds@1952
   298
	}
ds@1952
   299
private:
ds@1952
   300
	CPlugin *me;
ds@1952
   301
	IPluginFunction *m_pFunction;
ds@1952
   302
	IDBDriver *m_pDriver;
ds@1952
   303
	IDatabase *m_pDatabase;
ds@1952
   304
	char dbname[64];
ds@1952
   305
	char error[255];
ds@1952
   306
	cell_t m_Data;
ds@1952
   307
};
ds@1952
   308
ds@1952
   309
static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
ds@1952
   310
{
ds@1952
   311
	char *conf, *err;
ds@1952
   312
ds@1952
   313
	size_t maxlength = (size_t)params[4];
ds@1952
   314
	bool persistent = params[2] ? true : false;
ds@1952
   315
	pContext->LocalToString(params[1], &conf);
ds@1952
   316
	pContext->LocalToString(params[3], &err);
ds@1952
   317
	
ds@1952
   318
	IDBDriver *driver;
ds@1952
   319
	IDatabase *db;
ds@1952
   320
	if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
ds@1952
   321
	{
ds@1952
   322
		return BAD_HANDLE;
ds@1952
   323
	}
ds@1952
   324
ds@1952
   325
	Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
ds@1952
   326
	if (!hndl)
ds@1952
   327
	{
ds@1952
   328
		db->Close();
ds@1952
   329
		return BAD_HANDLE;
ds@1952
   330
	}
ds@1952
   331
ds@1952
   332
	/* HACK! Add us to the dependency list */
ds@1952
   333
	CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
ds@1952
   334
	if (pExt)
ds@1952
   335
	{
ds@1952
   336
		g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
ds@1952
   337
	}
ds@1952
   338
ds@1952
   339
	return hndl;
ds@1952
   340
}
ds@1952
   341
ds@1952
   342
static cell_t SQL_TConnect(IPluginContext *pContext, const cell_t *params)
ds@1952
   343
{
ds@1952
   344
	IPluginFunction *pf = pContext->GetFunctionById(params[1]);
ds@1952
   345
	if (!pf)
ds@1952
   346
	{
ds@1952
   347
		return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
ds@1952
   348
	}
ds@1952
   349
ds@1952
   350
	char *conf;
ds@1952
   351
	pContext->LocalToString(params[2], &conf);
ds@1952
   352
ds@1952
   353
	IDBDriver *driver = NULL;
ds@1952
   354
	const DatabaseInfo *pInfo = g_DBMan.FindDatabaseConf(conf);
ds@1952
   355
	char error[255];
ds@1952
   356
	if (pInfo != NULL)
ds@1952
   357
	{
ds@1952
   358
		if (pInfo->driver[0] == '\0')
ds@1952
   359
		{
ds@1952
   360
			driver = g_DBMan.GetDefaultDriver();
ds@1952
   361
		} else {
ds@1952
   362
			driver = g_DBMan.FindOrLoadDriver(pInfo->driver);
ds@1952
   363
		}
ds@1952
   364
		if (!driver)
ds@1952
   365
		{
ds@1952
   366
			UTIL_Format(error, 
ds@1952
   367
				sizeof(error), 
ds@1952
   368
				"Could not find driver \"%s\"", 
ds@1952
   369
				pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName() : pInfo->driver);
ds@1952
   370
		} else if (!driver->IsThreadSafe()) {
ds@1952
   371
			UTIL_Format(error,
ds@1952
   372
				sizeof(error),
ds@1952
   373
				"Driver \"%s\" is not thread safe!",
ds@1952
   374
				driver->GetIdentifier());
ds@1952
   375
		}
ds@1952
   376
	} else {
ds@1952
   377
		UTIL_Format(error, sizeof(error), "Could not find database conf \"%s\"", conf);
ds@1952
   378
	}
ds@1952
   379
ds@1952
   380
	if (!pInfo || !driver)
ds@1952
   381
	{
ds@1952
   382
		pf->PushCell(BAD_HANDLE);
ds@1952
   383
		pf->PushCell(BAD_HANDLE);
ds@1952
   384
		pf->PushString(error);
ds@1952
   385
		pf->PushCell(0);
ds@1952
   386
		pf->Execute(NULL);
ds@1952
   387
		return 0;
ds@1952
   388
	}
ds@1952
   389
ds@1952
   390
	/* HACK! Add us to the dependency list */
ds@1952
   391
	CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
ds@1952
   392
	if (pExt)
ds@1952
   393
	{
ds@1952
   394
		g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
ds@1952
   395
	}
ds@1952
   396
ds@1952
   397
	/* Finally, add to the thread if we can */
ds@1952
   398
	TConnectOp *op = new TConnectOp(pf, driver, conf, params[3]);
ds@1952
   399
	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
ds@1952
   400
	if (pPlugin->GetProperty("DisallowDBThreads", NULL)
ds@1952
   401
		|| !g_DBMan.AddToThreadQueue(op, PrioQueue_High))
ds@1952
   402
	{
ds@1952
   403
		/* Do everything right now */
ds@1952
   404
		op->RunThreadPart();
ds@1952
   405
		op->RunThinkPart();
ds@1952
   406
		op->Destroy();
ds@1952
   407
	}
ds@1952
   408
ds@1952
   409
	return 1;
ds@1952
   410
}
ds@1952
   411
ds@1952
   412
static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
ds@1952
   413
{
ds@1952
   414
	IDBDriver *driver;
ds@1952
   415
	if (params[1] == BAD_HANDLE)
ds@1952
   416
	{
ds@1952
   417
		if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
ds@1952
   418
		{
ds@1952
   419
			return pContext->ThrowNativeError("Could not find any default driver");
ds@1952
   420
		}
ds@1952
   421
	} else {
ds@1952
   422
		HandleError err;
ds@1952
   423
		if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
ds@1952
   424
			!= HandleError_None)
ds@1952
   425
		{
ds@1952
   426
			return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
ds@1952
   427
		}
ds@1952
   428
	}
ds@1952
   429
 
ds@1952
   430
	char *host, *user, *pass, *database, *error;
ds@1952
   431
	size_t maxlength = (size_t)params[7];
ds@1952
   432
	bool persistent = params[8] ? true : false;
ds@1952
   433
	unsigned int port = params[9];
ds@1952
   434
	unsigned int maxTimeout = params[10];
ds@1952
   435
	pContext->LocalToString(params[2], &host);
ds@1952
   436
	pContext->LocalToString(params[3], &user);
ds@1952
   437
	pContext->LocalToString(params[4], &pass);
ds@1952
   438
	pContext->LocalToString(params[5], &database);
ds@1952
   439
	pContext->LocalToString(params[6], &error);
ds@1952
   440
ds@1952
   441
	DatabaseInfo info;
ds@1952
   442
	info.database = database;
ds@1952
   443
	info.driver = driver->GetIdentifier();
ds@1952
   444
	info.host = host;
ds@1952
   445
	info.maxTimeout = maxTimeout;
ds@1952
   446
	info.pass = pass;
ds@1952
   447
	info.port = port;
ds@1952
   448
	info.user = user;
ds@1952
   449
	
ds@1952
   450
	IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
ds@1952
   451
ds@1952
   452
	if (db)
ds@1952
   453
	{
ds@1952
   454
		Handle_t hndl = g_DBMan.CreateHandle(DBHandle_Database, db, pContext->GetIdentity());
ds@1952
   455
		if (!hndl)
ds@1952
   456
		{
ds@1952
   457
			db->Close();
ds@1952
   458
			return BAD_HANDLE;
ds@1952
   459
		}
ds@1952
   460
ds@1952
   461
		/* HACK! Add us to the dependency list */
ds@1952
   462
		CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
ds@1952
   463
		if (pExt)
ds@1952
   464
		{
ds@1952
   465
			g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
ds@1952
   466
		}
ds@1952
   467
ds@1952
   468
		return hndl;
ds@1952
   469
	}
ds@1952
   470
	
ds@1952
   471
	return BAD_HANDLE;
ds@1952
   472
}
ds@1952
   473
ds@1952
   474
static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
ds@1952
   475
{
ds@1952
   476
	IDBDriver *driver;
ds@1952
   477
	if (params[1] == BAD_HANDLE)
ds@1952
   478
	{
ds@1952
   479
		if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
ds@1952
   480
		{
ds@1952
   481
			return pContext->ThrowNativeError("Could not find any default driver");
ds@1952
   482
		}
ds@1952
   483
	} else {
ds@1952
   484
		HandleError err;
ds@1952
   485
		if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
ds@1952
   486
			!= HandleError_None)
ds@1952
   487
		{
ds@1952
   488
			return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
ds@1952
   489
		}
ds@1952
   490
	}
ds@1952
   491
ds@1952
   492
	pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
ds@1952
   493
ds@1952
   494
	return 1;
ds@1952
   495
}
ds@1952
   496
ds@1952
   497
static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
ds@1952
   498
{
ds@1952
   499
	char *name;
ds@1952
   500
	pContext->LocalToString(params[1], &name);
ds@1952
   501
ds@1952
   502
	IDBDriver *driver = NULL;
ds@1952
   503
	if (name[0] == '\0')
ds@1952
   504
	{
ds@1952
   505
		driver = g_DBMan.GetDefaultDriver();
ds@1952
   506
	} else {
ds@1952
   507
		driver = g_DBMan.FindOrLoadDriver(name);
ds@1952
   508
	}
ds@1952
   509
ds@1952
   510
	return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
ds@1952
   511
}
ds@1952
   512
ds@1952
   513
static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
ds@1952
   514
{
ds@1952
   515
	IDBDriver *driver;
ds@1952
   516
	if (params[1] == BAD_HANDLE)
ds@1952
   517
	{
ds@1952
   518
		if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
ds@1952
   519
		{
ds@1952
   520
			return pContext->ThrowNativeError("Could not find any default driver");
ds@1952
   521
		}
ds@1952
   522
	} else {
ds@1952
   523
		HandleError err;
ds@1952
   524
		if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
ds@1952
   525
			!= HandleError_None)
ds@1952
   526
		{
ds@1952
   527
			return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
ds@1952
   528
		}
ds@1952
   529
	}
ds@1952
   530
ds@1952
   531
	pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
ds@1952
   532
ds@1952
   533
	return 1;
ds@1952
   534
}
ds@1952
   535
ds@1952
   536
static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
ds@1952
   537
{
ds@1952
   538
	IDatabase *db = NULL;
ds@1952
   539
	IPreparedQuery *stmt = NULL;
ds@1952
   540
	HandleError err;
ds@1952
   541
ds@1952
   542
	if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
ds@1952
   543
	{
ds@1952
   544
		return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
ds@1952
   545
	}
ds@1952
   546
ds@1952
   547
	if (db)
ds@1952
   548
	{
ds@1952
   549
		return db->GetAffectedRows();
ds@1952
   550
	} else if (stmt) {
ds@1952
   551
		return stmt->GetAffectedRows();
ds@1952
   552
	}
ds@1952
   553
ds@1952
   554
	return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
ds@1952
   555
}
ds@1952
   556
ds@1952
   557
static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
ds@1952
   558
{
ds@1952
   559
	IDatabase *db = NULL;
ds@1952
   560
	IPreparedQuery *stmt = NULL;
ds@1952
   561
	HandleError err;
ds@1952
   562
ds@1952
   563
	if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
ds@1952
   564
	{
ds@1952
   565
		return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
ds@1952
   566
	}
ds@1952
   567
ds@1952
   568
	if (db)
ds@1952
   569
	{
ds@1952
   570
		return db->GetInsertID();
ds@1952
   571
	} else if (stmt) {
ds@1952
   572
		return stmt->GetInsertID();
ds@1952
   573
	}
ds@1952
   574
ds@1952
   575
	return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
ds@1952
   576
}
ds@1952
   577
ds@1952
   578
static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
ds@1952
   579
{
ds@1952
   580
	IDatabase *db = NULL;
ds@1952
   581
	IPreparedQuery *stmt = NULL;
ds@1952
   582
	HandleError err;
ds@1952
   583
ds@1952
   584
	if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
ds@1952
   585
	{
ds@1952
   586
		return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
ds@1952
   587
	}
ds@1952
   588
ds@1952
   589
	const char *error = "";
ds@1952
   590
	if (db)
ds@1952
   591
	{
ds@1952
   592
		error = db->GetError();
ds@1952
   593
	} else if (stmt) {
ds@1952
   594
		error = stmt->GetError();
ds@1952
   595
	}
ds@1952
   596
ds@1952
   597
	if (error[0] == '\0')
ds@1952
   598
	{
ds@1952
   599
		return false;
ds@1952
   600
	}
ds@1952
   601
ds@1952
   602
	pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
ds@1952
   603
ds@1952
   604
	return 1;
ds@1952
   605
}
ds@1952
   606
ds@1952
   607
static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
ds@1952
   608
{
ds@1952
   609
	IDatabase *db = NULL;
ds@1952
   610
	HandleError err;
ds@1952
   611
ds@1952
   612
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   613
		!= HandleError_None)
ds@1952
   614
	{
ds@1952
   615
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   616
	}
ds@1952
   617
ds@1952
   618
	char *input, *output;
ds@1952
   619
	size_t maxlength = (size_t)params[4];
ds@1952
   620
	pContext->LocalToString(params[2], &input);
ds@1952
   621
	pContext->LocalToString(params[3], &output);
ds@1952
   622
ds@1952
   623
	size_t written;
ds@1952
   624
	bool s = db->QuoteString(input, output, maxlength, &written);
ds@1952
   625
ds@1952
   626
	cell_t *addr;
ds@1952
   627
	pContext->LocalToPhysAddr(params[5], &addr);
ds@1952
   628
	*addr = (cell_t)written;
ds@1952
   629
ds@1952
   630
	return s ? 1 : 0;
ds@1952
   631
}
ds@1952
   632
ds@1952
   633
static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
ds@1952
   634
{
ds@1952
   635
	IDatabase *db = NULL;
ds@1952
   636
	HandleError err;
ds@1952
   637
ds@1952
   638
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   639
		!= HandleError_None)
ds@1952
   640
	{
ds@1952
   641
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   642
	}
ds@1952
   643
ds@1952
   644
	char *query;
ds@1952
   645
	pContext->LocalToString(params[2], &query);
ds@1952
   646
ds@1952
   647
	if (params[0] >= 3 && params[3] != -1)
ds@1952
   648
	{
ds@1952
   649
		return db->DoSimpleQueryEx(query, params[3]) ? 1 : 0;
ds@1952
   650
	}
ds@1952
   651
ds@1952
   652
	return db->DoSimpleQuery(query) ? 1 : 0;
ds@1952
   653
}
ds@1952
   654
ds@1952
   655
static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
ds@1952
   656
{
ds@1952
   657
	IDatabase *db = NULL;
ds@1952
   658
	HandleError err;
ds@1952
   659
ds@1952
   660
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   661
		!= HandleError_None)
ds@1952
   662
	{
ds@1952
   663
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   664
	}
ds@1952
   665
ds@1952
   666
	char *query;
ds@1952
   667
	pContext->LocalToString(params[2], &query);
ds@1952
   668
ds@1952
   669
	IQuery *qr;
ds@1952
   670
	
ds@1952
   671
	if (params[0] >= 3 && params[3] != -1)
ds@1952
   672
	{
ds@1952
   673
		qr = db->DoQueryEx(query, params[3]);
ds@1952
   674
	}
ds@1952
   675
	else
ds@1952
   676
	{
ds@1952
   677
		qr = db->DoQuery(query);
ds@1952
   678
	}
ds@1952
   679
ds@1952
   680
	if (!qr)
ds@1952
   681
	{
ds@1952
   682
		return BAD_HANDLE;
ds@1952
   683
	}
ds@1952
   684
ds@1952
   685
	Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
ds@1952
   686
	if (hndl == BAD_HANDLE)
ds@1952
   687
	{
ds@1952
   688
		qr->Destroy();
ds@1952
   689
		return BAD_HANDLE;
ds@1952
   690
	}
ds@1952
   691
ds@1952
   692
	return hndl;
ds@1952
   693
}
ds@1952
   694
ds@1952
   695
static cell_t SQL_TQuery(IPluginContext *pContext, const cell_t *params)
ds@1952
   696
{
ds@1952
   697
	IDatabase *db = NULL;
ds@1952
   698
	HandleError err;
ds@1952
   699
ds@1952
   700
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   701
		!= HandleError_None)
ds@1952
   702
	{
ds@1952
   703
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   704
	}
ds@1952
   705
ds@1952
   706
	if (!db->GetDriver()->IsThreadSafe())
ds@1952
   707
	{
ds@1952
   708
		return pContext->ThrowNativeError("Driver \"%s\" is not thread safe!", db->GetDriver()->GetIdentifier());
ds@1952
   709
	}
ds@1952
   710
ds@1952
   711
	IPluginFunction *pf = pContext->GetFunctionById(params[2]);
ds@1952
   712
	if (!pf)
ds@1952
   713
	{
ds@1952
   714
		return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
ds@1952
   715
	}
ds@1952
   716
ds@1952
   717
	char *query;
ds@1952
   718
	pContext->LocalToString(params[3], &query);
ds@1952
   719
ds@1952
   720
	cell_t data = params[4];
ds@1952
   721
	PrioQueueLevel level = PrioQueue_Normal;
ds@1952
   722
	if (params[5] == (cell_t)PrioQueue_High)
ds@1952
   723
	{
ds@1952
   724
		level = PrioQueue_High;
ds@1952
   725
	} else if (params[5] == (cell_t)PrioQueue_Low) {
ds@1952
   726
		level = PrioQueue_Low;
ds@1952
   727
	}
ds@1952
   728
ds@1952
   729
	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
ds@1952
   730
ds@1952
   731
	TQueryOp *op = new TQueryOp(db, pf, query, data);
ds@1952
   732
	if (pPlugin->GetProperty("DisallowDBThreads", NULL)
ds@1952
   733
		|| !g_DBMan.AddToThreadQueue(op, level))
ds@1952
   734
	{
ds@1952
   735
		/* Do everything right now */
ds@1952
   736
		op->RunThreadPart();
ds@1952
   737
		op->RunThinkPart();
ds@1952
   738
		op->Destroy();
ds@1952
   739
	}
ds@1952
   740
ds@1952
   741
	return 1;
ds@1952
   742
}
ds@1952
   743
ds@1952
   744
static cell_t SQL_LockDatabase(IPluginContext *pContext, const cell_t *params)
ds@1952
   745
{
ds@1952
   746
	IDatabase *db = NULL;
ds@1952
   747
	HandleError err;
ds@1952
   748
ds@1952
   749
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   750
		!= HandleError_None)
ds@1952
   751
	{
ds@1952
   752
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   753
	}
ds@1952
   754
ds@1952
   755
	db->LockForFullAtomicOperation();
ds@1952
   756
ds@1952
   757
	return 1;
ds@1952
   758
}
ds@1952
   759
ds@1952
   760
static cell_t SQL_UnlockDatabase(IPluginContext *pContext, const cell_t *params)
ds@1952
   761
{
ds@1952
   762
	IDatabase *db = NULL;
ds@1952
   763
	HandleError err;
ds@1952
   764
ds@1952
   765
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   766
		!= HandleError_None)
ds@1952
   767
	{
ds@1952
   768
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   769
	}
ds@1952
   770
ds@1952
   771
	db->UnlockFromFullAtomicOperation();
ds@1952
   772
ds@1952
   773
	return 1;
ds@1952
   774
}
ds@1952
   775
ds@1952
   776
static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
ds@1952
   777
{
ds@1952
   778
	IDatabase *db = NULL;
ds@1952
   779
	HandleError err;
ds@1952
   780
ds@1952
   781
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
ds@1952
   782
		!= HandleError_None)
ds@1952
   783
	{
ds@1952
   784
		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
ds@1952
   785
	}
ds@1952
   786
ds@1952
   787
	char *query, *error;
ds@1952
   788
	size_t maxlength = (size_t)params[4];
ds@1952
   789
	pContext->LocalToString(params[2], &query);
ds@1952
   790
	pContext->LocalToString(params[3], &error);
ds@1952
   791
ds@1952
   792
	IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
ds@1952
   793
ds@1952
   794
	if (!qr)
ds@1952
   795
	{
ds@1952
   796
		return BAD_HANDLE;
ds@1952
   797
	}
ds@1952
   798
ds@1952
   799
	Handle_t hndl = g_HandleSys.CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
ds@1952
   800
	if (hndl == BAD_HANDLE)
ds@1952
   801
	{
ds@1952
   802
		qr->Destroy();
ds@1952
   803
		return BAD_HANDLE;
ds@1952
   804
	}
ds@1952
   805
ds@1952
   806
	return hndl;
ds@1952
   807
}
ds@1952
   808
ds@1952
   809
static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
ds@1952
   810
{
ds@1952
   811
	IQuery *query;
ds@1952
   812
	HandleError err;
ds@1952
   813
ds@1952
   814
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   815
	{
ds@1952
   816
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   817
	}
ds@1952
   818
ds@1952
   819
	return query->FetchMoreResults() ? 1 : 0;
ds@1952
   820
}
ds@1952
   821
ds@1952
   822
static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
ds@1952
   823
{
ds@1952
   824
	IQuery *query;
ds@1952
   825
	HandleError err;
ds@1952
   826
ds@1952
   827
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   828
	{
ds@1952
   829
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   830
	}
ds@1952
   831
ds@1952
   832
	return query->GetResultSet() != NULL ? true : false;
ds@1952
   833
}
ds@1952
   834
ds@1952
   835
static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
ds@1952
   836
{
ds@1952
   837
	IQuery *query;
ds@1952
   838
	HandleError err;
ds@1952
   839
ds@1952
   840
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   841
	{
ds@1952
   842
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   843
	}
ds@1952
   844
ds@1952
   845
	IResultSet *rs = query->GetResultSet();
ds@1952
   846
	if (!rs)
ds@1952
   847
	{
ds@1952
   848
		return 0;
ds@1952
   849
	}
ds@1952
   850
ds@1952
   851
	return rs->GetRowCount();
ds@1952
   852
}
ds@1952
   853
ds@1952
   854
static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
ds@1952
   855
{
ds@1952
   856
	IQuery *query;
ds@1952
   857
	HandleError err;
ds@1952
   858
ds@1952
   859
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   860
	{
ds@1952
   861
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   862
	}
ds@1952
   863
ds@1952
   864
	IResultSet *rs = query->GetResultSet();
ds@1952
   865
	if (!rs)
ds@1952
   866
	{
ds@1952
   867
		return 0;
ds@1952
   868
	}
ds@1952
   869
ds@1952
   870
	return rs->GetFieldCount();
ds@1952
   871
}
ds@1952
   872
ds@1952
   873
static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
ds@1952
   874
{
ds@1952
   875
	IQuery *query;
ds@1952
   876
	HandleError err;
ds@1952
   877
ds@1952
   878
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   879
	{
ds@1952
   880
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   881
	}
ds@1952
   882
ds@1952
   883
	IResultSet *rs = query->GetResultSet();
ds@1952
   884
	if (!rs)
ds@1952
   885
	{
ds@1952
   886
		return pContext->ThrowNativeError("No current result set");
ds@1952
   887
	}
ds@1952
   888
ds@1952
   889
	unsigned int field = params[2];
ds@1952
   890
ds@1952
   891
	const char *fldname;
ds@1952
   892
	if ((fldname = rs->FieldNumToName(field)) == NULL)
ds@1952
   893
	{
ds@1952
   894
		return pContext->ThrowNativeError("Invalid field index %d", field);
ds@1952
   895
	}
ds@1952
   896
ds@1952
   897
	pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
ds@1952
   898
ds@1952
   899
	return 1;
ds@1952
   900
}
ds@1952
   901
ds@1952
   902
static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
ds@1952
   903
{
ds@1952
   904
	IQuery *query;
ds@1952
   905
	HandleError err;
ds@1952
   906
ds@1952
   907
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   908
	{
ds@1952
   909
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   910
	}
ds@1952
   911
ds@1952
   912
	IResultSet *rs = query->GetResultSet();
ds@1952
   913
	if (!rs)
ds@1952
   914
	{
ds@1952
   915
		return pContext->ThrowNativeError("No current result set");
ds@1952
   916
	}
ds@1952
   917
ds@1952
   918
	char *field;
ds@1952
   919
	pContext->LocalToString(params[2], &field);
ds@1952
   920
ds@1952
   921
	cell_t *num;
ds@1952
   922
	pContext->LocalToPhysAddr(params[3], &num);
ds@1952
   923
ds@1952
   924
	return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
ds@1952
   925
}
ds@1952
   926
ds@1952
   927
static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
ds@1952
   928
{
ds@1952
   929
	IQuery *query;
ds@1952
   930
	HandleError err;
ds@1952
   931
ds@1952
   932
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   933
	{
ds@1952
   934
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   935
	}
ds@1952
   936
ds@1952
   937
	IResultSet *rs = query->GetResultSet();
ds@1952
   938
	if (!rs)
ds@1952
   939
	{
ds@1952
   940
		return pContext->ThrowNativeError("No current result set");
ds@1952
   941
	}
ds@1952
   942
ds@1952
   943
	return (rs->FetchRow() != NULL) ? true : false;
ds@1952
   944
}
ds@1952
   945
ds@1952
   946
static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
ds@1952
   947
{
ds@1952
   948
	IQuery *query;
ds@1952
   949
	HandleError err;
ds@1952
   950
ds@1952
   951
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   952
	{
ds@1952
   953
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   954
	}
ds@1952
   955
ds@1952
   956
	IResultSet *rs = query->GetResultSet();
ds@1952
   957
	if (!rs)
ds@1952
   958
	{
ds@1952
   959
		return pContext->ThrowNativeError("No current result set");
ds@1952
   960
	}
ds@1952
   961
ds@1952
   962
	return rs->MoreRows() ? 1 : 0;
ds@1952
   963
}
ds@1952
   964
ds@1952
   965
static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
ds@1952
   966
{
ds@1952
   967
	IQuery *query;
ds@1952
   968
	HandleError err;
ds@1952
   969
ds@1952
   970
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   971
	{
ds@1952
   972
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   973
	}
ds@1952
   974
ds@1952
   975
	IResultSet *rs = query->GetResultSet();
ds@1952
   976
	if (!rs)
ds@1952
   977
	{
ds@1952
   978
		return pContext->ThrowNativeError("No current result set");
ds@1952
   979
	}
ds@1952
   980
ds@1952
   981
	return rs->Rewind() ? 1 : 0;
ds@1952
   982
}
ds@1952
   983
ds@1952
   984
static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
ds@1952
   985
{
ds@1952
   986
	IQuery *query;
ds@1952
   987
	HandleError err;
ds@1952
   988
ds@1952
   989
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
   990
	{
ds@1952
   991
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
   992
	}
ds@1952
   993
ds@1952
   994
	IResultSet *rs = query->GetResultSet();
ds@1952
   995
	if (!rs)
ds@1952
   996
	{
ds@1952
   997
		return pContext->ThrowNativeError("No current result set");
ds@1952
   998
	}
ds@1952
   999
ds@1952
  1000
	IResultRow *row = rs->CurrentRow();
ds@1952
  1001
	if (!row)
ds@1952
  1002
	{
ds@1952
  1003
		return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952
  1004
	}
ds@1952
  1005
ds@1952
  1006
	const char *str;
ds@1952
  1007
	size_t length;
ds@1952
  1008
	DBResult res = row->GetString(params[2], &str, &length);
ds@1952
  1009
ds@1952
  1010
	if (res == DBVal_Error)
ds@1952
  1011
	{
ds@1952
  1012
		return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
ds@1952
  1013
	} else if (res == DBVal_TypeMismatch) {
ds@1952
  1014
		return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
ds@1952
  1015
	}
ds@1952
  1016
ds@1952
  1017
	pContext->StringToLocalUTF8(params[3], params[4], str, &length);
ds@1952
  1018
ds@1952
  1019
	cell_t *addr;
ds@1952
  1020
	pContext->LocalToPhysAddr(params[5], &addr);
ds@1952
  1021
	*addr = (cell_t)res;
ds@1952
  1022
ds@1952
  1023
	return (cell_t)length;
ds@1952
  1024
}
ds@1952
  1025
ds@1952
  1026
static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
ds@1952
  1027
{
ds@1952
  1028
	IQuery *query;
ds@1952
  1029
	HandleError err;
ds@1952
  1030
ds@1952
  1031
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
  1032
	{
ds@1952
  1033
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
  1034
	}
ds@1952
  1035
ds@1952
  1036
	IResultSet *rs = query->GetResultSet();
ds@1952
  1037
	if (!rs)
ds@1952
  1038
	{
ds@1952
  1039
		return pContext->ThrowNativeError("No current result set");
ds@1952
  1040
	}
ds@1952
  1041
ds@1952
  1042
	IResultRow *row = rs->CurrentRow();
ds@1952
  1043
	if (!row)
ds@1952
  1044
	{
ds@1952
  1045
		return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952
  1046
	}
ds@1952
  1047
ds@1952
  1048
	float f;
ds@1952
  1049
	DBResult res = row->GetFloat(params[2], &f);
ds@1952
  1050
ds@1952
  1051
	if (res == DBVal_Error)
ds@1952
  1052
	{
ds@1952
  1053
		return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
ds@1952
  1054
	} else if (res == DBVal_TypeMismatch) {
ds@1952
  1055
		return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
ds@1952
  1056
	}
ds@1952
  1057
ds@1952
  1058
	cell_t *addr;
ds@1952
  1059
	pContext->LocalToPhysAddr(params[3], &addr);
ds@1952
  1060
	*addr = (cell_t)res;
ds@1952
  1061
ds@1952
  1062
	return sp_ftoc(f);
ds@1952
  1063
}
ds@1952
  1064
ds@1952
  1065
static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
ds@1952
  1066
{
ds@1952
  1067
	IQuery *query;
ds@1952
  1068
	HandleError err;
ds@1952
  1069
ds@1952
  1070
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
  1071
	{
ds@1952
  1072
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
  1073
	}
ds@1952
  1074
ds@1952
  1075
	IResultSet *rs = query->GetResultSet();
ds@1952
  1076
	if (!rs)
ds@1952
  1077
	{
ds@1952
  1078
		return pContext->ThrowNativeError("No current result set");
ds@1952
  1079
	}
ds@1952
  1080
ds@1952
  1081
	IResultRow *row = rs->CurrentRow();
ds@1952
  1082
	if (!row)
ds@1952
  1083
	{
ds@1952
  1084
		return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952
  1085
	}
ds@1952
  1086
ds@1952
  1087
	int iv;
ds@1952
  1088
	DBResult res = row->GetInt(params[2], &iv);
ds@1952
  1089
ds@1952
  1090
	if (res == DBVal_Error)
ds@1952
  1091
	{
ds@1952
  1092
		return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
ds@1952
  1093
	} else if (res == DBVal_TypeMismatch) {
ds@1952
  1094
		return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
ds@1952
  1095
	}
ds@1952
  1096
ds@1952
  1097
	cell_t *addr;
ds@1952
  1098
	pContext->LocalToPhysAddr(params[3], &addr);
ds@1952
  1099
	*addr = (cell_t)res;
ds@1952
  1100
ds@1952
  1101
	return iv;
ds@1952
  1102
}
ds@1952
  1103
ds@1952
  1104
static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
ds@1952
  1105
{
ds@1952
  1106
	IQuery *query;
ds@1952
  1107
	HandleError err;
ds@1952
  1108
ds@1952
  1109
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
  1110
	{
ds@1952
  1111
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
  1112
	}
ds@1952
  1113
ds@1952
  1114
	IResultSet *rs = query->GetResultSet();
ds@1952
  1115
	if (!rs)
ds@1952
  1116
	{
ds@1952
  1117
		return pContext->ThrowNativeError("No current result set");
ds@1952
  1118
	}
ds@1952
  1119
ds@1952
  1120
	IResultRow *row = rs->CurrentRow();
ds@1952
  1121
	if (!row)
ds@1952
  1122
	{
ds@1952
  1123
		return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952
  1124
	}
ds@1952
  1125
ds@1952
  1126
	if ((unsigned)params[2] >= rs->GetFieldCount())
ds@1952
  1127
	{
ds@1952
  1128
		return pContext->ThrowNativeError("Invalid field index %d", params[2]);
ds@1952
  1129
	}
ds@1952
  1130
ds@1952
  1131
	return row->IsNull(params[2]) ? 1 : 0;
ds@1952
  1132
}
ds@1952
  1133
ds@1952
  1134
static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
ds@1952
  1135
{
ds@1952
  1136
	IQuery *query;
ds@1952
  1137
	HandleError err;
ds@1952
  1138
ds@1952
  1139
	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
ds@1952
  1140
	{
ds@1952
  1141
		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
ds@1952
  1142
	}
ds@1952
  1143
ds@1952
  1144
	IResultSet *rs = query->GetResultSet();
ds@1952
  1145
	if (!rs)
ds@1952
  1146
	{
ds@1952
  1147
		return pContext->ThrowNativeError("No current result set");
ds@1952
  1148
	}
ds@1952
  1149
ds@1952
  1150
	IResultRow *row = rs->CurrentRow();
ds@1952
  1151
	if (!row)
ds@1952
  1152
	{
ds@1952
  1153
		return pContext->ThrowNativeError("Current result set has no fetched rows");
ds@1952
  1154
	}
ds@1952
  1155
ds@1952
  1156
	if ((unsigned)params[2] >= rs->GetFieldCount())
ds@1952
  1157
	{
ds@1952
  1158
		return pContext->ThrowNativeError("Invalid field index %d", params[2]);
ds@1952
  1159
	}
ds@1952
  1160
ds@1952
  1161
	return row->GetDataSize(params[2]);
ds@1952
  1162
}
ds@1952
  1163
ds@1952
  1164
static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
ds@1952
  1165
{
ds@1952
  1166
	IPreparedQuery *stmt;
ds@1952
  1167
	HandleError err;
ds@1952
  1168
ds@1952
  1169
	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952
  1170
	{
ds@1952
  1171
		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952
  1172
	}
ds@1952
  1173
ds@1952
  1174
	if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
ds@1952
  1175
	{
ds@1952
  1176
		return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
ds@1952
  1177
	}
ds@1952
  1178
ds@1952
  1179
	return 1;
ds@1952
  1180
}
ds@1952
  1181
ds@1952
  1182
static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
ds@1952
  1183
{
ds@1952
  1184
	IPreparedQuery *stmt;
ds@1952
  1185
	HandleError err;
ds@1952
  1186
ds@1952
  1187
	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952
  1188
	{
ds@1952
  1189
		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952
  1190
	}
ds@1952
  1191
ds@1952
  1192
	if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
ds@1952
  1193
	{
ds@1952
  1194
		return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
ds@1952
  1195
	}
ds@1952
  1196
ds@1952
  1197
	return 1;
ds@1952
  1198
}
ds@1952
  1199
ds@1952
  1200
static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
ds@1952
  1201
{
ds@1952
  1202
	IPreparedQuery *stmt;
ds@1952
  1203
	HandleError err;
ds@1952
  1204
ds@1952
  1205
	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952
  1206
	{
ds@1952
  1207
		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952
  1208
	}
ds@1952
  1209
ds@1952
  1210
	char *str;
ds@1952
  1211
	pContext->LocalToString(params[3], &str);
ds@1952
  1212
ds@1952
  1213
	if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
ds@1952
  1214
	{
ds@1952
  1215
		return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
ds@1952
  1216
	}
ds@1952
  1217
ds@1952
  1218
	return 1;
ds@1952
  1219
}
ds@1952
  1220
ds@1952
  1221
static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
ds@1952
  1222
{
ds@1952
  1223
	IPreparedQuery *stmt;
ds@1952
  1224
	HandleError err;
ds@1952
  1225
ds@1952
  1226
	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
ds@1952
  1227
	{
ds@1952
  1228
		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
ds@1952
  1229
	}
ds@1952
  1230
ds@1952
  1231
	return stmt->Execute() ? 1 : 0;
ds@1952
  1232
}
ds@1952
  1233
ds@1952
  1234
static cell_t SQL_IsSameConnection(IPluginContext *pContext, const cell_t *params)
ds@1952
  1235
{
ds@1952
  1236
	IDatabase *db1=NULL, *db2=NULL;
ds@1952
  1237
	HandleError err;
ds@1952
  1238
ds@1952
  1239
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
ds@1952
  1240
		!= HandleError_None)
ds@1952
  1241
	{
ds@1952
  1242
		return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
ds@1952
  1243
	}
ds@1952
  1244
ds@1952
  1245
	if ((err = g_DBMan.ReadHandle(params[2], DBHandle_Database, (void **)&db2))
ds@1952
  1246
		!= HandleError_None)
ds@1952
  1247
	{
ds@1952
  1248
		return pContext->ThrowNativeError("Invalid database Handle 2/%x (error: %d)", params[2], err);
ds@1952
  1249
	}
ds@1952
  1250
ds@1952
  1251
	return (db1 == db2) ? true : false;
ds@1952
  1252
}
ds@1952
  1253
ds@1952
  1254
static cell_t SQL_ReadDriver(IPluginContext *pContext, const cell_t *params)
ds@1952
  1255
{
ds@1952
  1256
	IDatabase *db1=NULL;
ds@1952
  1257
	HandleError err;
ds@1952
  1258
ds@1952
  1259
	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db1))
ds@1952
  1260
		!= HandleError_None)
ds@1952
  1261
	{
ds@1952
  1262
		return pContext->ThrowNativeError("Invalid database Handle 1/%x (error: %d)", params[1], err);
ds@1952
  1263
	}
ds@1952
  1264
ds@1952
  1265
	IDBDriver *driver = db1->GetDriver();
ds@1952
  1266
ds@1952
  1267
	pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
ds@1952
  1268
ds@1952
  1269
	return driver->GetHandle();
ds@1952
  1270
}
ds@1952
  1271
ds@1952
  1272
static cell_t SQL_CheckConfig(IPluginContext *pContext, const cell_t *params)
ds@1952
  1273
{
ds@1952
  1274
	char *name;
ds@1952
  1275
	pContext->LocalToString(params[1], &name);
ds@1952
  1276
ds@1952
  1277
	return (g_DBMan.FindDatabaseConf(name) != NULL) ? 1 : 0;
ds@1952
  1278
}
ds@1952
  1279
ds@1952
  1280
REGISTER_NATIVES(dbNatives)
ds@1952
  1281
{
ds@1952
  1282
	{"SQL_BindParamInt",		SQL_BindParamInt},
ds@1952
  1283
	{"SQL_BindParamFloat",		SQL_BindParamFloat},
ds@1952
  1284
	{"SQL_BindParamString",		SQL_BindParamString},\
ds@1952
  1285
	{"SQL_CheckConfig",			SQL_CheckConfig},
ds@1952
  1286
	{"SQL_Connect",				SQL_Connect},
ds@1952
  1287
	{"SQL_ConnectEx",			SQL_ConnectEx},
ds@1952
  1288
	{"SQL_EscapeString",		SQL_QuoteString},
ds@1952
  1289
	{"SQL_Execute",				SQL_Execute},
ds@1952
  1290
	{"SQL_FastQuery",			SQL_FastQuery},
ds@1952
  1291
	{"SQL_FetchFloat",			SQL_FetchFloat},
ds@1952
  1292
	{"SQL_FetchInt",			SQL_FetchInt},
ds@1952
  1293
	{"SQL_FetchMoreResults",	SQL_FetchMoreResults},
ds@1952
  1294
	{"SQL_FetchRow",			SQL_FetchRow},
ds@1952
  1295
	{"SQL_FetchSize",			SQL_FetchSize},
ds@1952
  1296
	{"SQL_FetchString",			SQL_FetchString},
ds@1952
  1297
	{"SQL_FieldNameToNum",		SQL_FieldNameToNum},
ds@1952
  1298
	{"SQL_FieldNumToName",		SQL_FieldNumToName},
ds@1952
  1299
	{"SQL_GetAffectedRows",		SQL_GetAffectedRows},
ds@1952
  1300
	{"SQL_GetDriver",			SQL_GetDriver},
ds@1952
  1301
	{"SQL_GetDriverIdent",		SQL_GetDriverIdent},
ds@1952
  1302
	{"SQL_GetDriverProduct",	SQL_GetDriverProduct},
ds@1952
  1303
	{"SQL_GetError",			SQL_GetError},
ds@1952
  1304
	{"SQL_GetFieldCount",		SQL_GetFieldCount},
ds@1952
  1305
	{"SQL_GetInsertId",			SQL_GetInsertId},
ds@1952
  1306
	{"SQL_GetRowCount",			SQL_GetRowCount},
ds@1952
  1307
	{"SQL_HasResultSet",		SQL_HasResultSet},
ds@1952
  1308
	{"SQL_IsFieldNull",			SQL_IsFieldNull},
ds@1952
  1309
	{"SQL_IsSameConnection",	SQL_IsSameConnection},
ds@1952
  1310
	{"SQL_LockDatabase",		SQL_LockDatabase},
ds@1952
  1311
	{"SQL_MoreRows",			SQL_MoreRows},
ds@1952
  1312
	{"SQL_PrepareQuery",		SQL_PrepareQuery},
ds@1952
  1313
	{"SQL_Query",				SQL_Query},
ds@1952
  1314
	{"SQL_QuoteString",			SQL_QuoteString},
ds@1952
  1315
	{"SQL_ReadDriver",			SQL_ReadDriver},
ds@1952
  1316
	{"SQL_Rewind",				SQL_Rewind},
ds@1952
  1317
	{"SQL_TConnect",			SQL_TConnect},
ds@1952
  1318
	{"SQL_TQuery",				SQL_TQuery},
ds@1952
  1319
	{"SQL_UnlockDatabase",		SQL_UnlockDatabase},
ds@1952
  1320
	{NULL,						NULL},
ds@1952
  1321
};