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