amxmodx/modules/sqlite/basic_sql.cpp

633 lines
13 KiB
C++
Raw Normal View History

// vim: set ts=4 sw=4 tw=99 noet:
//
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
// Copyright (C) The AMX Mod X Development Team.
//
// This software is licensed under the GNU General Public License, version 3 or higher.
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
// https://alliedmods.net/amxmodx-license
//
// SQLite Module
//
2006-06-03 19:52:21 +00:00
#include <stdio.h>
#include "sh_list.h"
#include "sqlite_header.h"
#include "sqlheaders.h"
SqliteDriver g_Sqlite;
void FreeConnection(void *p, unsigned int num)
{
SQL_Connection *cn = (SQL_Connection *)p;
free(cn->host);
free(cn->user);
free(cn->pass);
free(cn->db);
delete cn;
}
void FreeQuery(void *p, unsigned int num)
{
AmxQueryInfo *qry = (AmxQueryInfo *)p;
qry->pQuery->FreeHandle();
delete qry;
}
void FreeDatabase(void *p, unsigned int num)
{
IDatabase *db = (IDatabase *)p;
db->FreeHandle();
}
static cell AMX_NATIVE_CALL SQL_MakeDbTuple(AMX *amx, cell *params)
{
SQL_Connection *sql = new SQL_Connection;
int len;
sql->port = 0;
sql->host = strdup("");
sql->user = strdup("");
sql->pass = strdup("");
2006-06-03 19:52:21 +00:00
char *db = MF_GetAmxString(amx, params[4], 0, &len);
char path[255];
FILE *fp;
MF_BuildPathnameR(path, sizeof(path), "%s", db);
if ((fp=fopen(path, "rb")))
2006-06-03 19:52:21 +00:00
{
fclose(fp);
sql->db = strdup(path);
2006-06-03 19:52:21 +00:00
} else {
MF_BuildPathnameR(path, sizeof(path), "%s/sqlite3/%s.sq3",
MF_GetLocalInfo("amxx_datadir", "addons/amxmodx/data"),
db);
sql->db = strdup(path);
2006-06-03 19:52:21 +00:00
}
unsigned int num = MakeHandle(sql, Handle_Connection, FreeConnection);
return num;
}
static cell AMX_NATIVE_CALL SQL_FreeHandle(AMX *amx, cell *params)
{
if (!FreeHandle(params[1]))
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid handle: %d", params[1]);
return 0;
}
return 1;
}
static cell AMX_NATIVE_CALL SQL_Connect(AMX *amx, cell *params)
{
SQL_Connection *sql = (SQL_Connection *)GetHandle(params[1], Handle_Connection);
if (!sql)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid handle: %d", params[1]);
return 0;
}
DatabaseInfo nfo;
nfo.database = sql->db;
nfo.user = "";
nfo.pass = "";
nfo.port = 0;
nfo.host = "";
char buffer[512];
int errcode;
IDatabase *pDb = g_Sqlite.Connect(&nfo, &errcode, buffer, sizeof(buffer)-1);
if (!pDb)
{
cell *c_err = MF_GetAmxAddr(amx, params[2]);
*c_err = errcode;
MF_SetAmxString(amx, params[3], buffer, params[4]);
return 0;
}
return MakeHandle(pDb, Handle_Database, FreeDatabase);
}
static cell AMX_NATIVE_CALL SQL_PrepareQuery(AMX *amx, cell *params)
{
IDatabase *pDb = (IDatabase *)GetHandle(params[1], Handle_Database);
if (!pDb)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid database handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
int len;
char *fmt = MF_FormatAmxString(amx, params, 2, &len);
IQuery *pQuery = pDb->PrepareQuery(fmt);
if (!pQuery)
return 0;
AmxQueryInfo *qinfo = new AmxQueryInfo;
qinfo->pQuery = pQuery;
memset(&qinfo->info, 0, sizeof(QueryInfo));
return MakeHandle(qinfo, Handle_Query, FreeQuery);
}
static cell AMX_NATIVE_CALL SQL_Execute(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
qInfo->error[0] = '\0';
memset(&qInfo->info, 0, sizeof(QueryInfo));
2006-08-28 19:17:26 +00:00
if (!qInfo->pQuery->Execute2(&qInfo->info, qInfo->error, 254))
{
2006-06-03 19:52:21 +00:00
return 0;
}
2006-06-03 19:52:21 +00:00
return 1;
}
static cell AMX_NATIVE_CALL SQL_QueryError(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
MF_SetAmxString(amx, params[2], qInfo->error, params[3]);
return qInfo->info.errorcode;
}
static cell AMX_NATIVE_CALL SQL_MoreResults(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
if (!qInfo->info.rs)
return 0;
return (qInfo->info.rs->IsDone() ? 0 : 1);
}
static cell AMX_NATIVE_CALL SQL_IsNull(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs || rs->IsDone())
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
unsigned int col = static_cast<unsigned int>(params[2]);
if (col >= rs->FieldCount())
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid column: %d", col);
return 0;
}
IResultRow *rr = rs->GetRow();
return rr->IsNull(col) ? 1 : 0;
}
static cell AMX_NATIVE_CALL SQL_ReadResult(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs || rs->IsDone())
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
IResultRow *row = rs->GetRow();
unsigned int col = static_cast<unsigned int>(params[2]);
if (col >= rs->FieldCount())
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid column: %d", col);
return 0;
}
cell numparams = params[0] / sizeof(cell);
switch (numparams)
{
case 4:
{
const char *str = row->GetString(col);
if (!str)
str = "";
cell *len = MF_GetAmxAddr(amx, params[4]);
MF_SetAmxString(amx, params[3], str, (int)*len);
break;
}
case 3:
{
REAL num = row->GetFloat(col);
cell *addr = MF_GetAmxAddr(amx, params[3]);
*addr = amx_ftoc(num);
break;
}
case 2:
{
int num = row->GetInt(col);
return num;
break;
}
default:
{
MF_LogError(amx, AMX_ERR_NATIVE, "Bad number of arguments passed.");
break;
}
}
return 1;
}
static cell AMX_NATIVE_CALL SQL_NextRow(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs || rs->IsDone())
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
rs->NextRow();
return 1;
}
static cell AMX_NATIVE_CALL SQL_AffectedRows(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
return static_cast<cell>(qInfo->info.affected_rows);
}
static cell AMX_NATIVE_CALL SQL_NumResults(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs)
{
return 0;
}
return rs->RowCount();
}
static cell AMX_NATIVE_CALL SQL_NumColumns(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
return rs->FieldCount();
}
static cell AMX_NATIVE_CALL SQL_FieldNumToName(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
unsigned int col = static_cast<unsigned int>(params[2]);
const char *namewa = rs->FieldNumToName(col);
if (!namewa)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid column: %d", col);
return 0;
}
MF_SetAmxString(amx, params[3], namewa, params[4]);
return 1;
}
static cell AMX_NATIVE_CALL SQL_GetQueryString(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo || (!qInfo->pQuery && !qInfo->opt_ptr))
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
return 0;
}
const char *ptr = qInfo->pQuery ? qInfo->pQuery->GetQueryString() : qInfo->opt_ptr;
return MF_SetAmxString(amx, params[2], ptr, params[3]);
}
2006-06-03 19:52:21 +00:00
static cell AMX_NATIVE_CALL SQL_FieldNameToNum(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
2006-06-03 19:52:21 +00:00
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
int len;
char *namewa = MF_GetAmxString(amx, params[2], 0, &len);
unsigned int columnId;
if (!rs->FieldNameToNum(namewa, &columnId))
{
2006-06-03 19:52:21 +00:00
return -1;
}
2006-06-03 19:52:21 +00:00
return columnId;
}
2006-08-28 19:17:26 +00:00
static cell AMX_NATIVE_CALL SQL_GetInsertId(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
return 0;
}
return qInfo->info.insert_id;
}
2006-06-03 19:52:21 +00:00
static cell AMX_NATIVE_CALL SQL_GetAffinity(AMX *amx, cell *params)
{
return MF_SetAmxString(amx, params[1], g_Sqlite.NameString(), params[2]);
}
static cell AMX_NATIVE_CALL SQL_SetAffinity(AMX *amx, cell *params)
{
int len;
char *str = MF_GetAmxString(amx, params[1], 0, &len);
2006-06-04 19:40:34 +00:00
if (!str[0])
{
return 1;
}
2006-06-03 19:52:21 +00:00
if (stricmp(str, g_Sqlite.NameString()) == 0)
{
return 1;
}
SqlFunctions *pFuncs = (SqlFunctions *)MF_RequestFunction(SQL_DRIVER_FUNC);
while (pFuncs)
{
if (pFuncs->driver->IsCompatDriver(str))
{
return pFuncs->set_affinity(amx);
}
pFuncs = pFuncs->prev;
}
return 0;
}
static cell AMX_NATIVE_CALL SQL_Rewind(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
rs->Rewind();
return 1;
}
static cell AMX_NATIVE_CALL SQL_NextResultSet(AMX *amx, cell *params)
{
AmxQueryInfo *qInfo = (AmxQueryInfo *)GetHandle(params[1], Handle_Query);
if (!qInfo)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid query handle: %d", params[1]);
return 0;
}
IResultSet *rs = qInfo->info.rs;
if (!rs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "No result set in this query!");
return 0;
}
if (rs->NextResultSet())
{
return 1;
}
else
{
qInfo->info.rs = NULL;
return 0;
}
}
static cell AMX_NATIVE_CALL SQL_QuoteString(AMX *amx, cell *params)
{
int len;
char *str = MF_GetAmxString(amx, params[4], 0, &len);
size_t newsize;
static char buffer[8192];
if (params[1] != 0)
{
IDatabase *pDb = (IDatabase *)GetHandle(params[1], Handle_Database);
if (!pDb)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid database handle: %d", params[1]);
return 0;
}
if (pDb->QuoteString(str, buffer, sizeof(buffer)-1, &newsize) == 0)
{
MF_SetAmxString(amx, params[2], buffer, params[3]);
return newsize;
} else {
return -1;
}
} else {
if (g_Sqlite.QuoteString(str, buffer, sizeof(buffer)-1, &newsize) == 0)
{
MF_SetAmxString(amx, params[2], buffer, params[3]);
return newsize;
} else {
return -1;
}
}
}
static cell AMX_NATIVE_CALL SQL_QuoteStringFmt(AMX *amx, cell *params)
{
int len;
char *str = MF_FormatAmxString(amx, params, 4, &len);
size_t newsize;
static char buffer[8192];
if (params[1] != 0)
{
IDatabase *pDb = (IDatabase *)GetHandle(params[1], Handle_Database);
if (!pDb)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid database handle: %d", params[1]);
return 0;
}
if (pDb->QuoteString(str, buffer, sizeof(buffer)-1, &newsize) == 0)
{
MF_SetAmxString(amx, params[2], buffer, params[3]);
return newsize;
} else {
return -1;
}
} else {
if (g_Sqlite.QuoteString(str, buffer, sizeof(buffer)-1, &newsize) == 0)
{
MF_SetAmxString(amx, params[2], buffer, params[3]);
return newsize;
} else {
return -1;
}
}
}
static cell AMX_NATIVE_CALL SQL_SetCharset(AMX *amx, cell *params)
{
/* SQLite supports only UTF-8/16 */
return 0;
}
AMX_NATIVE_INFO g_BaseSqlNatives[] =
2006-06-03 19:52:21 +00:00
{
{"SQL_MakeDbTuple", SQL_MakeDbTuple},
{"SQL_FreeHandle", SQL_FreeHandle},
{"SQL_Connect", SQL_Connect},
{"SQL_PrepareQuery", SQL_PrepareQuery},
{"SQL_Execute", SQL_Execute},
{"SQL_QueryError", SQL_QueryError},
{"SQL_MoreResults", SQL_MoreResults},
{"SQL_IsNull", SQL_IsNull},
{"SQL_ReadResult", SQL_ReadResult},
{"SQL_NextRow", SQL_NextRow},
{"SQL_AffectedRows", SQL_AffectedRows},
{"SQL_NumResults", SQL_NumResults},
{"SQL_NumColumns", SQL_NumColumns},
{"SQL_FieldNumToName", SQL_FieldNumToName},
{"SQL_FieldNameToNum", SQL_FieldNameToNum},
{"SQL_GetAffinity", SQL_GetAffinity},
{"SQL_SetAffinity", SQL_SetAffinity},
2006-08-28 19:17:26 +00:00
{"SQL_GetInsertId", SQL_GetInsertId},
{"SQL_GetQueryString", SQL_GetQueryString},
{"SQL_Rewind", SQL_Rewind},
{"SQL_QuoteString", SQL_QuoteString},
{"SQL_QuoteStringFmt", SQL_QuoteStringFmt},
{"SQL_NextResultSet", SQL_NextResultSet},
{"SQL_SetCharset", SQL_SetCharset},
2006-06-03 19:52:21 +00:00
{NULL, NULL},
};