core/smn_database.cpp
author Scott Ehlert <ds@alliedmods.net>
Fri Jun 01 06:33:54 2007 +0000 (2007-06-01)
changeset 873 a2136b3be10d
parent 869 caa5587e708a
child 875 4a1451bf0925
permissions -rw-r--r--
- Added natives: PrintToChat() and PrintCenterText()
- Bit of reorganization with moving some natives from sourcemod.inc to halflife.inc
     1 #include "sm_globals.h"
     2 #include "HandleSys.h"
     3 #include "Database.h"
     4 #include "ExtensionSys.h"
     5 #include "PluginSys.h"
     6 
     7 HandleType_t hQueryType;
     8 HandleType_t hStmtType;
     9 
    10 class DatabaseHelpers : 
    11 	public SMGlobalClass,
    12 	public IHandleTypeDispatch
    13 {
    14 public:
    15 	virtual void OnSourceModAllInitialized()
    16 	{
    17 		HandleAccess acc;
    18 
    19 		/* Disable cloning */
    20 		g_HandleSys.InitAccessDefaults(NULL, &acc);
    21 		acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
    22 
    23 		TypeAccess tacc;
    24 
    25 		g_HandleSys.InitAccessDefaults(&tacc, NULL);
    26 		tacc.ident = g_pCoreIdent;
    27 
    28 		hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
    29 		hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, g_pCoreIdent, NULL);
    30 	}
    31 
    32 	virtual void OnSourceModShutdown()
    33 	{
    34 		g_HandleSys.RemoveType(hStmtType, g_pCoreIdent);
    35 		g_HandleSys.RemoveType(hQueryType, g_pCoreIdent);
    36 	}
    37 
    38 	virtual void OnHandleDestroy(HandleType_t type, void *object)
    39 	{
    40 		if (type == hQueryType)
    41 		{
    42 			IQuery *query = (IQuery *)object;
    43 			query->Destroy();
    44 		} else if (type == hStmtType) {
    45 			IPreparedQuery *query = (IPreparedQuery *)object;
    46 			query->Destroy();
    47 		}
    48 	}
    49 } s_DatabaseNativeHelpers;
    50 
    51 //is this safe for stmt handles? i think since it's single inheritance, it always will be.
    52 inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
    53 {
    54 	HandleSecurity sec;
    55 	sec.pOwner = pContext->GetIdentity();
    56 	sec.pIdentity = g_pCoreIdent;
    57 
    58 	return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query);
    59 }
    60 
    61 inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
    62 {
    63 	HandleSecurity sec;
    64 	sec.pOwner = pContext->GetIdentity();
    65 	sec.pIdentity = g_pCoreIdent;
    66 
    67 	return g_HandleSys.ReadHandle(hndl, hStmtType, &sec, (void **)query);
    68 }
    69 
    70 inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
    71 {
    72 	HandleError err;
    73 	if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
    74 	{
    75 		*db = NULL;
    76 		return ReadStmtHndl(hndl, pContext, query);
    77 	}
    78 	return err;
    79 }
    80 
    81 static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
    82 {
    83 	char *conf, *err;
    84 
    85 	size_t maxlength = (size_t)params[4];
    86 	bool persistent = params[2] ? true : false;
    87 	pContext->LocalToString(params[1], &conf);
    88 	pContext->LocalToString(params[3], &err);
    89 	
    90 	IDBDriver *driver;
    91 	IDatabase *db;
    92 	if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
    93 	{
    94 		return BAD_HANDLE;
    95 	}
    96 
    97 	/* HACK! Add us to the dependency list */
    98 	CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
    99 	if (pExt)
   100 	{
   101 		g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
   102 	}
   103 
   104 	return db->GetHandle();
   105 }
   106 
   107 static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
   108 {
   109 	IDBDriver *driver;
   110 	if (params[1] == BAD_HANDLE)
   111 	{
   112 		if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
   113 		{
   114 			return pContext->ThrowNativeError("Could not find any default driver");
   115 		}
   116 	} else {
   117 		HandleError err;
   118 		if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
   119 			!= HandleError_None)
   120 		{
   121 			return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
   122 		}
   123 	}
   124  
   125 	char *host, *user, *pass, *database, *error;
   126 	size_t maxlength = (size_t)params[7];
   127 	bool persistent = params[8] ? true : false;
   128 	unsigned int port = params[9];
   129 	unsigned int maxTimeout = params[10];
   130 	pContext->LocalToString(params[2], &host);
   131 	pContext->LocalToString(params[3], &user);
   132 	pContext->LocalToString(params[4], &pass);
   133 	pContext->LocalToString(params[5], &database);
   134 	pContext->LocalToString(params[6], &error);
   135 
   136 	DatabaseInfo info;
   137 	info.database = database;
   138 	info.driver = driver->GetIdentifier();
   139 	info.host = host;
   140 	info.maxTimeout = maxTimeout;
   141 	info.pass = pass;
   142 	info.port = port;
   143 	info.user = user;
   144 	
   145 	IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
   146 
   147 	if (db)
   148 	{
   149 		/* HACK! Add us to the dependency list */
   150 		CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
   151 		if (pExt)
   152 		{
   153 			g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
   154 		}
   155 
   156 		return db->GetHandle();
   157 	}
   158 	
   159 	return BAD_HANDLE;
   160 }
   161 
   162 static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	IDBDriver *driver;
   165 	if (params[1] == BAD_HANDLE)
   166 	{
   167 		if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
   168 		{
   169 			return pContext->ThrowNativeError("Could not find any default driver");
   170 		}
   171 	} else {
   172 		HandleError err;
   173 		if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
   174 			!= HandleError_None)
   175 		{
   176 			return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
   177 		}
   178 	}
   179 
   180 	pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
   181 
   182 	return 1;
   183 }
   184 
   185 static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
   186 {
   187 	char *name;
   188 	pContext->LocalToString(params[1], &name);
   189 
   190 	IDBDriver *driver = NULL;
   191 	if (name[0] == '\0')
   192 	{
   193 		driver = g_DBMan.GetDefaultDriver();
   194 	} else {
   195 		driver = g_DBMan.FindOrLoadDriver(name);
   196 	}
   197 
   198 	return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
   199 }
   200 
   201 static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
   202 {
   203 	IDBDriver *driver;
   204 	if (params[1] == BAD_HANDLE)
   205 	{
   206 		if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
   207 		{
   208 			return pContext->ThrowNativeError("Could not find any default driver");
   209 		}
   210 	} else {
   211 		HandleError err;
   212 		if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
   213 			!= HandleError_None)
   214 		{
   215 			return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
   216 		}
   217 	}
   218 
   219 	pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
   220 
   221 	return 1;
   222 }
   223 
   224 static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
   225 {
   226 	IDatabase *db = NULL;
   227 	IPreparedQuery *stmt = NULL;
   228 	HandleError err;
   229 
   230 	if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
   231 	{
   232 		return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
   233 	}
   234 
   235 	if (db)
   236 	{
   237 		return db->GetAffectedRows();
   238 	} else if (stmt) {
   239 		return stmt->GetAffectedRows();
   240 	}
   241 
   242 	return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
   243 }
   244 
   245 static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
   246 {
   247 	IDatabase *db = NULL;
   248 	IPreparedQuery *stmt = NULL;
   249 	HandleError err;
   250 
   251 	if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
   252 	{
   253 		return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
   254 	}
   255 
   256 	if (db)
   257 	{
   258 		return db->GetInsertID();
   259 	} else if (stmt) {
   260 		return stmt->GetInsertID();
   261 	}
   262 
   263 	return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
   264 }
   265 
   266 static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
   267 {
   268 	IDatabase *db = NULL;
   269 	IPreparedQuery *stmt = NULL;
   270 	HandleError err;
   271 
   272 	if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
   273 	{
   274 		return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
   275 	}
   276 
   277 	const char *error = "";
   278 	if (db)
   279 	{
   280 		error = db->GetError();
   281 	} else if (stmt) {
   282 		error = stmt->GetError();
   283 	}
   284 
   285 	if (error[0] == '\0')
   286 	{
   287 		return false;
   288 	}
   289 
   290 	pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
   291 
   292 	return 1;
   293 }
   294 
   295 static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
   296 {
   297 	IDatabase *db = NULL;
   298 	HandleError err;
   299 
   300 	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
   301 		!= HandleError_None)
   302 	{
   303 		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
   304 	}
   305 
   306 	char *input, *output;
   307 	size_t maxlength = (size_t)params[4];
   308 	pContext->LocalToString(params[2], &input);
   309 	pContext->LocalToString(params[3], &output);
   310 
   311 	size_t written;
   312 	bool s = db->QuoteString(input, output, maxlength, &written);
   313 
   314 	cell_t *addr;
   315 	pContext->LocalToPhysAddr(params[5], &addr);
   316 	*addr = (cell_t)written;
   317 
   318 	return s ? 1 : 0;
   319 }
   320 
   321 static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
   322 {
   323 	IDatabase *db = NULL;
   324 	HandleError err;
   325 
   326 	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
   327 		!= HandleError_None)
   328 	{
   329 		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
   330 	}
   331 
   332 	char *query;
   333 	pContext->LocalToString(params[2], &query);
   334 
   335 	return db->DoSimpleQuery(query) ? 1 : 0;
   336 }
   337 
   338 static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
   339 {
   340 	IDatabase *db = NULL;
   341 	HandleError err;
   342 
   343 	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
   344 		!= HandleError_None)
   345 	{
   346 		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
   347 	}
   348 
   349 	char *query;
   350 	pContext->LocalToString(params[2], &query);
   351 
   352 	IQuery *qr = db->DoQuery(query);
   353 
   354 	if (!qr)
   355 	{
   356 		return BAD_HANDLE;
   357 	}
   358 
   359 	Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
   360 	if (hndl == BAD_HANDLE)
   361 	{
   362 		qr->Destroy();
   363 		return BAD_HANDLE;
   364 	}
   365 
   366 	return hndl;
   367 }
   368 
   369 static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
   370 {
   371 	IDatabase *db = NULL;
   372 	HandleError err;
   373 
   374 	if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
   375 		!= HandleError_None)
   376 	{
   377 		return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
   378 	}
   379 
   380 	char *query, *error;
   381 	size_t maxlength = (size_t)params[4];
   382 	pContext->LocalToString(params[2], &query);
   383 	pContext->LocalToString(params[3], &error);
   384 
   385 	IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
   386 
   387 	if (!qr)
   388 	{
   389 		return BAD_HANDLE;
   390 	}
   391 
   392 	Handle_t hndl = g_HandleSys.CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
   393 	if (hndl == BAD_HANDLE)
   394 	{
   395 		qr->Destroy();
   396 		return BAD_HANDLE;
   397 	}
   398 
   399 	return hndl;
   400 }
   401 
   402 static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
   403 {
   404 	IQuery *query;
   405 	HandleError err;
   406 
   407 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   408 	{
   409 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   410 	}
   411 
   412 	return query->FetchMoreResults() ? 1 : 0;
   413 }
   414 
   415 static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
   416 {
   417 	IQuery *query;
   418 	HandleError err;
   419 
   420 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   421 	{
   422 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   423 	}
   424 
   425 	return query->GetResultSet() != NULL ? true : false;
   426 }
   427 
   428 static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
   429 {
   430 	IQuery *query;
   431 	HandleError err;
   432 
   433 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   434 	{
   435 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   436 	}
   437 
   438 	IResultSet *rs = query->GetResultSet();
   439 	if (!rs)
   440 	{
   441 		return 0;
   442 	}
   443 
   444 	return rs->GetRowCount();
   445 }
   446 
   447 static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
   448 {
   449 	IQuery *query;
   450 	HandleError err;
   451 
   452 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   453 	{
   454 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   455 	}
   456 
   457 	IResultSet *rs = query->GetResultSet();
   458 	if (!rs)
   459 	{
   460 		return 0;
   461 	}
   462 
   463 	return rs->GetFieldCount();
   464 }
   465 
   466 static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
   467 {
   468 	IQuery *query;
   469 	HandleError err;
   470 
   471 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   472 	{
   473 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   474 	}
   475 
   476 	IResultSet *rs = query->GetResultSet();
   477 	if (!rs)
   478 	{
   479 		return pContext->ThrowNativeError("No current result set");
   480 	}
   481 
   482 	unsigned int field = params[2];
   483 
   484 	const char *fldname;
   485 	if ((fldname = rs->FieldNumToName(field)) == NULL)
   486 	{
   487 		return pContext->ThrowNativeError("Invalid field index %d", field);
   488 	}
   489 
   490 	pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
   491 
   492 	return 1;
   493 }
   494 
   495 static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
   496 {
   497 	IQuery *query;
   498 	HandleError err;
   499 
   500 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   501 	{
   502 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   503 	}
   504 
   505 	IResultSet *rs = query->GetResultSet();
   506 	if (!rs)
   507 	{
   508 		return pContext->ThrowNativeError("No current result set");
   509 	}
   510 
   511 	char *field;
   512 	pContext->LocalToString(params[2], &field);
   513 
   514 	cell_t *num;
   515 	pContext->LocalToPhysAddr(params[3], &num);
   516 
   517 	return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
   518 }
   519 
   520 static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
   521 {
   522 	IQuery *query;
   523 	HandleError err;
   524 
   525 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   526 	{
   527 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   528 	}
   529 
   530 	IResultSet *rs = query->GetResultSet();
   531 	if (!rs)
   532 	{
   533 		return pContext->ThrowNativeError("No current result set");
   534 	}
   535 
   536 	return (rs->FetchRow() != NULL) ? true : false;
   537 }
   538 
   539 static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
   540 {
   541 	IQuery *query;
   542 	HandleError err;
   543 
   544 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   545 	{
   546 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   547 	}
   548 
   549 	IResultSet *rs = query->GetResultSet();
   550 	if (!rs)
   551 	{
   552 		return pContext->ThrowNativeError("No current result set");
   553 	}
   554 
   555 	return rs->MoreRows() ? 1 : 0;
   556 }
   557 
   558 static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
   559 {
   560 	IQuery *query;
   561 	HandleError err;
   562 
   563 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   564 	{
   565 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   566 	}
   567 
   568 	IResultSet *rs = query->GetResultSet();
   569 	if (!rs)
   570 	{
   571 		return pContext->ThrowNativeError("No current result set");
   572 	}
   573 
   574 	return rs->Rewind() ? 1 : 0;
   575 }
   576 
   577 static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
   578 {
   579 	IQuery *query;
   580 	HandleError err;
   581 
   582 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   583 	{
   584 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   585 	}
   586 
   587 	IResultSet *rs = query->GetResultSet();
   588 	if (!rs)
   589 	{
   590 		return pContext->ThrowNativeError("No current result set");
   591 	}
   592 
   593 	IResultRow *row = rs->CurrentRow();
   594 	if (!row)
   595 	{
   596 		return pContext->ThrowNativeError("Current result set has no fetched rows");
   597 	}
   598 
   599 	const char *str;
   600 	size_t length;
   601 	DBResult res = row->GetString(params[2], &str, &length);
   602 
   603 	if (res == DBVal_Error)
   604 	{
   605 		return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
   606 	} else if (res == DBVal_TypeMismatch) {
   607 		return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
   608 	}
   609 
   610 	pContext->StringToLocalUTF8(params[3], params[4], str, &length);
   611 
   612 	cell_t *addr;
   613 	pContext->LocalToPhysAddr(params[5], &addr);
   614 	*addr = (cell_t)res;
   615 
   616 	return (cell_t)length;
   617 }
   618 
   619 static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
   620 {
   621 	IQuery *query;
   622 	HandleError err;
   623 
   624 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   625 	{
   626 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   627 	}
   628 
   629 	IResultSet *rs = query->GetResultSet();
   630 	if (!rs)
   631 	{
   632 		return pContext->ThrowNativeError("No current result set");
   633 	}
   634 
   635 	IResultRow *row = rs->CurrentRow();
   636 	if (!row)
   637 	{
   638 		return pContext->ThrowNativeError("Current result set has no fetched rows");
   639 	}
   640 
   641 	float f;
   642 	DBResult res = row->GetFloat(params[2], &f);
   643 
   644 	if (res == DBVal_Error)
   645 	{
   646 		return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
   647 	} else if (res == DBVal_TypeMismatch) {
   648 		return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
   649 	}
   650 
   651 	cell_t *addr;
   652 	pContext->LocalToPhysAddr(params[5], &addr);
   653 	*addr = (cell_t)res;
   654 
   655 	return sp_ftoc(f);
   656 }
   657 
   658 static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
   659 {
   660 	IQuery *query;
   661 	HandleError err;
   662 
   663 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   664 	{
   665 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   666 	}
   667 
   668 	IResultSet *rs = query->GetResultSet();
   669 	if (!rs)
   670 	{
   671 		return pContext->ThrowNativeError("No current result set");
   672 	}
   673 
   674 	IResultRow *row = rs->CurrentRow();
   675 	if (!row)
   676 	{
   677 		return pContext->ThrowNativeError("Current result set has no fetched rows");
   678 	}
   679 
   680 	int iv;
   681 	DBResult res = row->GetInt(params[2], &iv);
   682 
   683 	if (res == DBVal_Error)
   684 	{
   685 		return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
   686 	} else if (res == DBVal_TypeMismatch) {
   687 		return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
   688 	}
   689 
   690 	cell_t *addr;
   691 	pContext->LocalToPhysAddr(params[5], &addr);
   692 	*addr = (cell_t)res;
   693 
   694 	return iv;
   695 }
   696 
   697 static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
   698 {
   699 	IQuery *query;
   700 	HandleError err;
   701 
   702 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   703 	{
   704 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   705 	}
   706 
   707 	IResultSet *rs = query->GetResultSet();
   708 	if (!rs)
   709 	{
   710 		return pContext->ThrowNativeError("No current result set");
   711 	}
   712 
   713 	IResultRow *row = rs->CurrentRow();
   714 	if (!row)
   715 	{
   716 		return pContext->ThrowNativeError("Current result set has no fetched rows");
   717 	}
   718 
   719 	if ((unsigned)params[2] >= rs->GetFieldCount())
   720 	{
   721 		return pContext->ThrowNativeError("Invalid field index %d", params[2]);
   722 	}
   723 
   724 	return row->IsNull(params[2]) ? 1 : 0;
   725 }
   726 
   727 static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
   728 {
   729 	IQuery *query;
   730 	HandleError err;
   731 
   732 	if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
   733 	{
   734 		return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
   735 	}
   736 
   737 	IResultSet *rs = query->GetResultSet();
   738 	if (!rs)
   739 	{
   740 		return pContext->ThrowNativeError("No current result set");
   741 	}
   742 
   743 	IResultRow *row = rs->CurrentRow();
   744 	if (!row)
   745 	{
   746 		return pContext->ThrowNativeError("Current result set has no fetched rows");
   747 	}
   748 
   749 	if ((unsigned)params[2] >= rs->GetFieldCount())
   750 	{
   751 		return pContext->ThrowNativeError("Invalid field index %d", params[2]);
   752 	}
   753 
   754 	return row->GetDataSize(params[2]);
   755 }
   756 
   757 static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
   758 {
   759 	IPreparedQuery *stmt;
   760 	HandleError err;
   761 
   762 	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
   763 	{
   764 		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
   765 	}
   766 
   767 	if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
   768 	{
   769 		return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
   770 	}
   771 
   772 	return 1;
   773 }
   774 
   775 static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
   776 {
   777 	IPreparedQuery *stmt;
   778 	HandleError err;
   779 
   780 	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
   781 	{
   782 		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
   783 	}
   784 
   785 	if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
   786 	{
   787 		return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
   788 	}
   789 
   790 	return 1;
   791 }
   792 
   793 static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
   794 {
   795 	IPreparedQuery *stmt;
   796 	HandleError err;
   797 
   798 	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
   799 	{
   800 		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
   801 	}
   802 
   803 	char *str;
   804 	pContext->LocalToString(params[3], &str);
   805 
   806 	if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
   807 	{
   808 		return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
   809 	}
   810 
   811 	return 1;
   812 }
   813 
   814 static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
   815 {
   816 	IPreparedQuery *stmt;
   817 	HandleError err;
   818 
   819 	if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
   820 	{
   821 		return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
   822 	}
   823 
   824 	return stmt->Execute() ? 1 : 0;
   825 }
   826 
   827 REGISTER_NATIVES(dbNatives)
   828 {
   829 	{"SQL_BindParamInt",		SQL_BindParamInt},
   830 	{"SQL_BindParamFloat",		SQL_BindParamFloat},
   831 	{"SQL_BindParamString",		SQL_BindParamString},
   832 	{"SQL_Connect",				SQL_Connect},
   833 	{"SQL_ConnectEx",			SQL_ConnectEx},
   834 	{"SQL_Execute",				SQL_Execute},
   835 	{"SQL_FastQuery",			SQL_FastQuery},
   836 	{"SQL_FetchFloat",			SQL_FetchFloat},
   837 	{"SQL_FetchInt",			SQL_FetchInt},
   838 	{"SQL_FetchMoreResults",	SQL_FetchMoreResults},
   839 	{"SQL_FetchRow",			SQL_FetchRow},
   840 	{"SQL_FetchSize",			SQL_FetchSize},
   841 	{"SQL_FetchString",			SQL_FetchString},
   842 	{"SQL_FieldNameToNum",		SQL_FieldNameToNum},
   843 	{"SQL_FieldNumToName",		SQL_FieldNumToName},
   844 	{"SQL_GetAffectedRows",		SQL_GetAffectedRows},
   845 	{"SQL_GetDriver",			SQL_GetDriver},
   846 	{"SQL_GetDriverIdent",		SQL_GetDriverIdent},
   847 	{"SQL_GetDriverProduct",	SQL_GetDriverProduct},
   848 	{"SQL_GetError",			SQL_GetError},
   849 	{"SQL_GetFieldCount",		SQL_GetFieldCount},
   850 	{"SQL_GetInsertId",			SQL_GetInsertId},
   851 	{"SQL_GetRowCount",			SQL_GetRowCount},
   852 	{"SQL_HasResultSet",		SQL_HasResultSet},
   853 	{"SQL_IsFieldNull",			SQL_IsFieldNull},
   854 	{"SQL_MoreRows",			SQL_MoreRows},
   855 	{"SQL_Query",				SQL_Query},
   856 	{"SQL_QuoteString",			SQL_QuoteString},
   857 	{"SQL_PrepareQuery",		SQL_PrepareQuery},
   858 	{"SQL_Rewind",				SQL_Rewind},
   859 	{NULL,						NULL},
   860 };