VIP Boost Банери Кредити
Основно Начало Сървъри Marketplace Новини Форум Сървъри
Общности Хостинг Добави Boost
Ресурси
Библиотеки Карти Видеа Магазин
Инструменти
Builder Demo CFG HUD
AMXX API
Вход Регистрация
/ Библиотеки / sqlvault.inc

sqlvault.inc

debug idea found from xs.inc

.inc 39.1 KB 1642 реда 04.04.2026
Pawn / AMX Mod X
#if defined _sqlv_included
	#endinput
#endif
#define _sqlv_included

#include <amxmodx>
#include <sqlx>

#if AMXX_VERSION_NUM >= 175
	#pragma reqlib sqlite
	#if !defined AMXMODX_NOAUTOLOAD
		#pragma loadlib sqlite
	#endif
#else
	#pragma library sqlite
#endif

// debug idea found from xs.inc
//#define SQLVAULT_DEBUG_LIB

#if defined SQLVAULT_DEBUG_LIB
	#define SQLVAULT_FUNC_ATTRIB
	#define SQLVAULT_VAR_ATTRIB new
#else
	#define SQLVAULT_FUNC_ATTRIB stock
	#define SQLVAULT_VAR_ATTRIB stock
#endif

SQLVAULT_VAR_ATTRIB const SQLVAULT_VERSION[] = "0.0.3";

SQLVAULT_VAR_ATTRIB __SQLVAULT_ERRCODE;
SQLVAULT_VAR_ATTRIB __SQLVAULT_ERROR[128];
SQLVAULT_VAR_ATTRIB __SQLVAULT_TEMPSTRING[1024];

enum SQLVault
{
	Invalid_SQLVault = 0
};

/*
 * Structure used for sqlv_read_all()
 * 
 * @elem		SQLV_Key - String that holds the key
 * @elem		SQLV_Data - String that holds the data
 * @elem		SQLV_TimeStamp - Integer that holds the timestamp
 * 
 */
enum _:SQLVaultEntry
{
	SQLV_Key[64],
	SQLV_Data[512],
	SQLV_TimeStamp
};

/*
 * Opens a vault database
 * 
 * @param		szHost - The host used to connect to the database
 * @param		szUser - The user used to connect to the database
 * @param		szPass - The password used to connect to the database
 * @param		szDb - The name of the database to connect to
 * @param		szVaultName - The vault name to open
 * @param		bAutoInit - If true, sqlv_init() is called inside the function. If false, sqlv_init() is not called.
 * 
 * @return		Returns a valid vault handle on success, Invalid_SQLVault on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB SQLVault:sqlv_open(szHost[], szUser[], szPass[], szDb[], szVaultName[], bool:bAutoInit = true)
{
	new Handle:hTuple = SQL_MakeDbTuple(szHost, szUser, szPass, szDb);
	
	if(hTuple == Empty_Handle)
	{
		log_amx("Could not create SQL tuple");
		
		return Invalid_SQLVault;
	}
	
	QuoteString(szVaultName, '`');
	
	new Trie:tVaultData = TrieCreate();
	
	TrieSetCell(tVaultData, "tuple", hTuple);
	TrieSetString(tVaultData, "vaultname", szVaultName);
	
	UnQuoteString(szVaultName, '`');
	
	if(bAutoInit && !sqlv_init(SQLVault:tVaultData))
	{
		SQL_FreeHandle(hTuple);
		
		TrieDestroy(tVaultData);
		
		return Invalid_SQLVault;
	}
	
	return SQLVault:tVaultData;
}

/*
 * Opens a vault database based on the amx_sql_* cvars in addons/amxmodx/configs/sql.cfg
 * 
 * @param		szVaultName - The vault name to open
 * @param		bAutoInit - If true, sqlv_init() is called inside the function. If false, sqlv_init() is not called.
 * 
 * @return		Returns a valid vault handle on success, Invalid_SQLVault on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB SQLVault:sqlv_open_default(szVaultName[], bool:bAutoInit = true)
{
	// code taken from SQL_MakeStdTuple()
	
	new szConfigsDir[64];
	get_localinfo("amxx_configsdir", szConfigsDir, charsmax(szConfigsDir));
	
	server_cmd("exec %s/sql.cfg", szConfigsDir);
	server_exec();
	
	new szHost[64], szUser[64], szPass[64], szDb[64], szSetType[12];
	get_cvar_string("amx_sql_host",	szHost,		charsmax(szHost));
	get_cvar_string("amx_sql_user",	szUser,		charsmax(szUser));
	get_cvar_string("amx_sql_pass",	szPass,		charsmax(szPass));
	get_cvar_string("amx_sql_db",	szDb,		charsmax(szDb));
	get_cvar_string("amx_sql_type",	szSetType,	charsmax(szSetType));
	
	if(!sqlv_affinity(szSetType))
	{
		return Invalid_SQLVault;
	}
	
	return sqlv_open(szHost, szUser, szPass, szDb, szVaultName, bAutoInit);
}

/*
 * Opens a local vault database using the sqlite module
 * 
 * @param		szVaultName - The vault name to open
 * @param		bAutoInit - If true, sqlv_init() is called inside the function. If false, sqlv_init() is not called.
 * 
 * @return		Returns a valid vault handle on success, Invalid_SQLVault on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB SQLVault:sqlv_open_local(szVaultName[], bool:bAutoInit = true)
{
	static SQLITE_HOST[] =	"127.0.0.1";
	static SQLITE_USER[] =	"root";
	static SQLITE_PASS[] =	"";
	static SQLITE_DB[] =	"amx";
	
	// added requirement for "sqlite" library at top of .inc
	/*if(!is_module_loaded("sqlite"))
	{
		log_amx("SQLite module needs to be enabled in modules.ini to open local database!");
		
		return Invalid_SQLVault;
	}*/
	
	if(!sqlv_affinity("sqlite"))
	{
		return Invalid_SQLVault;
	}
	
	return sqlv_open(SQLITE_HOST, SQLITE_USER, SQLITE_PASS, SQLITE_DB, szVaultName, bAutoInit);
}

/*
 * Sets the SQL driver
 * 
 * @param		szSetType - The driver to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_affinity(szSetType[])
{
	new szGetType[12];
	SQL_GetAffinity(szGetType, charsmax(szGetType));
	
	if(!equali(szGetType, szSetType) && !SQL_SetAffinity(szSetType))
	{
		log_amx("Failed to set affinity from %s to %s.", szGetType, szSetType);
		
		return 0;
	}
	
	return 1;
}

/*
 * Closes the vault
 * 
 * @param		hVault - The vault to close
 * 
 * @return		No return
 * 
 * @note		The vault handle is set to Invalid_SQLVault after it is closed.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_close(&SQLVault:hVault)
{
	if(hVault == Invalid_SQLVault)
	{
		return;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	SQL_FreeHandle(hTuple);
	
	if(TrieGetCell(Trie:hVault, "connection", hTuple))
	{
		SQL_FreeHandle(hTuple);
	}
	
	TrieDestroy(Trie:hVault);
	
	hVault = Invalid_SQLVault;
}

/*
 * Connects to the vault database
 * 
 * @param		hVault - The vault to connect to
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		This does not open the vault!
 * 			It only creates a cached connection.
 * 
 * @note		This should be used when multiple vault functions are used in a row
 * 			Doing this will reduce CPU usage in connecting/disconnecting each time those functions are used.
 * 
 * @note		After those functions are used, this connection should be closed.
 * 
 * @note		It is not recommended to keep the connection open the whole time the plugin is running.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_connect(SQLVault:hVault)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	if(TrieKeyExists(Trie:hVault, "connection"))
	{
		return 1;
	}
	
	new Handle:hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
	
	if(hConnection == Empty_Handle)
	{
		log_amx("Connection failed in sqlv_connect() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
		
		return 0;
	}
	
	TrieSetCell(Trie:hVault, "connection", hConnection);
	
	return 1;
}

/*
 * Disconnects from the vault database
 * 
 * @param		hVault - The vault to disconnect
 * 
 * @return		Returns 1 if disconnected, 0 on error or no connection existed.
 * 
 * @note		This does not close the vault!
 * 			It only closes the cached connection made.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_disconnect(SQLVault:hVault)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		return 0;
	}
	
	SQL_FreeHandle(hConnection);
	
	TrieDeleteKey(Trie:hVault, "connection");
	
	return 1;
}

/*
 * Initializes the vault for use
 * 
 * @param		hVault - The vault to initialize
 * 
 * @return		Returns 1 on success, 0 on failure
 * 
 * @note		This must be used before any other vault functions are used (except open and close)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_init(SQLVault:hVault)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_init() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"CREATE TABLE IF NOT EXISTS `%s` \
		(`key` VARCHAR(64) NOT NULL PRIMARY KEY, \
		`data` VARCHAR(512) NOT NULL, \
		`timestamp` INT(11) NOT NULL, \
		`permanent` INT(11) NOT NULL);",
		szVaultName);
	
	new iReturn = 1;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_init(): %s", __SQLVAULT_ERROR);
		
		iReturn = 0;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Gets a string value from a vault
 * 
 * @param		hVault - The vault to get the data from
 * @param		szKey - The key holding the data
 * @param		szData - The buffer to hold the data
 * @param		iDataLen - The max length of the data buffer
 * @param		iTimeStamp - The byref variable holding the timestamp
 * 
 * @return		Returns 1 on success, 0 on failure
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_get_data(SQLVault:hVault, szKey[], szData[], iDataLen, &iTimeStamp = 0)
{
	szData[0] = 0;
	
	iTimeStamp = 0;
	
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_get_data() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	QuoteString(szKey);
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"SELECT `data`, `timestamp` \
		FROM `%s` \
		WHERE `key` = '%s';",
		szVaultName, szKey);
	
	UnQuoteString(szKey);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_get_data(): %s", __SQLVAULT_ERROR);
	}
	else if((iReturn = SQL_NumResults(hQuery)))
	{
		SQL_ReadResult(hQuery, 0, szData, iDataLen);
		
		iTimeStamp = SQL_ReadResult(hQuery, 1);
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Gets an integer value from a vault
 * 
 * @param		hVault - The vault to get the data from
 * @param		szKey - The key holding the data
 * @param		iTimeStamp - The byref variable holding the timestamp
 * 
 * @return		Returns the integer value on success, 0 on failure
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_get_num(SQLVault:hVault, szKey[], &iTimeStamp = 0)
{
	if(sqlv_get_data(hVault, szKey, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING), iTimeStamp))
	{
		return str_to_num(__SQLVAULT_TEMPSTRING);
	}
	
	return 0;
}

/*
 * Gets a float value from a vault
 * 
 * @param		hVault - The vault to get the data from
 * @param		szKey - The key holding the data
 * @param		iTimeStamp - The byref variable holding the timestamp
 * 
 * @return		Returns the float value on success, 0.0 on failure
 * 
 */
SQLVAULT_FUNC_ATTRIB Float:sqlv_get_float(SQLVault:hVault, szKey[], &iTimeStamp = 0)
{
	if(sqlv_get_data(hVault, szKey, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING), iTimeStamp))
	{
		return str_to_float(__SQLVAULT_TEMPSTRING);
	}
	
	return 0.0;
}

/*
 * Checks if a key exists in a vault
 * 
 * @param		hVault - The vault to look in
 * @param		szKey - The key to look for
 * 
 * @return		Returns 1 if exists, 0 if it doesn't.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_key_exists(SQLVault:hVault, szKey[])
{
	return sqlv_get_data(hVault, szKey, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING));
}

/*
 * Sets a vault entry to a string value
 * 
 * @param		hVault - The vault to set the data in
 * @param		szKey - The key to hold the data
 * @param		szData - The string value to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Use "*" for the key to set all entries to that data.
 * 			This will update all the timestamps and also set all to non-permanent (even permanent entries)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_set_data(SQLVault:hVault, szKey[], szData[])
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_set_data() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	QuoteString(szData);
	
	new Handle:hQuery;
	
	if(equal(szKey, "*"))
	{
		hQuery = SQL_PrepareQuery(hConnection,\
			"UPDATE `%s` \
			SET `data` = '%s' \
			AND `timestamp` = %d \
			AND `permanent` = 0;",\
			szVaultName, szData, get_systime());
	}
	else
	{
		QuoteString(szKey);
		
		hQuery = SQL_PrepareQuery(hConnection,\
			"REPLACE INTO `%s` \
			(`key`, `data`, `timestamp`, `permanent`) \
			VALUES \
			('%s', '%s', %d, 0);",\
			szVaultName, szKey, szData, get_systime());
		
		UnQuoteString(szKey);
	}
	
	UnQuoteString(szData);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_set_data(): %s", __SQLVAULT_ERROR);
	}
	else
	{
		iReturn = 1;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Sets a vault entry to an integer value
 * 
 * @param		hVault - The vault to set the data in
 * @param		szKey - The key to hold the data
 * @param		iData - The integer value to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Use "*" for the key to set all entries to that data.
 * 			This will update all the timestamps and also set all to non-permanent (even permanent entries)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_set_num(SQLVault:hVault, szKey[], const iData)
{
	num_to_str(iData, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING));
	
	return sqlv_set_data(hVault, szKey, __SQLVAULT_TEMPSTRING);
}

/*
 * Sets a vault entry to a float value
 * 
 * @param		hVault - The vault to set the data in
 * @param		szKey - The key to hold the data
 * @param		flData - The float value to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Use "*" for the key to set all entries to that data.
 * 			This will update all the timestamps and also set all to non-permanent (even permanent entries)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_set_float(SQLVault:hVault, szKey[], Float:flData)
{
	float_to_str(flData, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING));
	
	return sqlv_set_data(hVault, szKey, __SQLVAULT_TEMPSTRING);
}

/*
 * Sets a vault entry to a string value with a permanent entry
 * 
 * @param		hVault - The vault to set the data in
 * @param		szKey - The key to hold the data
 * @param		szData - The string value to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Permanent means that the entry cannot be deleted by sqlv_prune().
 * 
 * @note		Use "*" for the key to set all entries to that data.
 * 			This will update all the timestamps and also set all to permanent (even non-permanent entries)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_pset_data(SQLVault:hVault, szKey[], szData[])
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_pset_data() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	QuoteString(szData);
	
	new Handle:hQuery;
	
	if(equal(szKey, "*"))
	{
		hQuery = SQL_PrepareQuery(hConnection,\
			"UPDATE `%s` \
			SET `data` = '%s' \
			AND `timestamp` = %d \
			AND `permanent` = 1;",\
			szVaultName, szData, get_systime());
	}
	else
	{
		QuoteString(szKey);
		
		hQuery = SQL_PrepareQuery(hConnection,\
			"REPLACE INTO `%s` \
			(`key`, `data`, `timestamp`, `permanent`) \
			VALUES \
			('%s', '%s', %d, 1);",\
			szVaultName, szKey, szData, get_systime());
		
		UnQuoteString(szKey);
	}
	
	UnQuoteString(szData);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_set_data(): %s", __SQLVAULT_ERROR);
	}
	else
	{
		iReturn = 1;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Sets a vault entry to an integer value with a permanent entry
 * 
 * @param		hVault - The vault to set the data in
 * @param		szKey - The key to hold the data
 * @param		iData - The integer value to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Permanent means that the entry cannot be deleted by sqlv_prune().
 * 
 * @note		Use "*" for the key to set all entries to that data.
 * 			This will update all the timestamps and also set all to permanent (even non-permanent entries)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_pset_num(SQLVault:hVault, szKey[], const iData)
{
	num_to_str(iData, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING));
	
	return sqlv_pset_data(hVault, szKey, __SQLVAULT_TEMPSTRING);
}

/*
 * Sets a vault entry to a float value with a permanent entry
 * 
 * @param		hVault - The vault to set the data in
 * @param		szKey - The key to hold the data
 * @param		flData - The float value to set
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Permanent means that the entry cannot be deleted by sqlv_prune().
 * 
 * @note		Use "*" for the key to set all entries to that data.
 * 			This will update all the timestamps and also set all to permanent (even non-permanent entries)!
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_pset_float(SQLVault:hVault, szKey[], Float:flData)
{
	float_to_str(flData, __SQLVAULT_TEMPSTRING, charsmax(__SQLVAULT_TEMPSTRING));
	
	return sqlv_pset_data(hVault, szKey, __SQLVAULT_TEMPSTRING);
}

/*
 * Removes a key from a vault
 * 
 * @param		hVault - The vault to delete the key from
 * @param		szKey - The key to delete
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_remove(SQLVault:hVault, szKey[])
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_remove() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	QuoteString(szKey);
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"DELETE FROM `%s` \
		WHERE `key` = '%s';",
		szVaultName, szKey);
	
	UnQuoteString(szKey);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_remove(): %s", __SQLVAULT_ERROR);
	}
	else if(!(iReturn = SQL_AffectedRows(hQuery)))
	{
		iReturn = 1;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Removes all non-permanent entries in a vault that have a timestamp between the start and end timestamps
 * 
 * @param		hVault - The vault to prune
 * @param		iStart - The start timestamp
 * @param		iEnd - The end timestamp
 * 
 * @return		Returns the number of deleted entries (or 1 if none deleted) on success, 0 on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_prune(SQLVault:hVault, iStart, iEnd)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_prune() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"DELETE FROM `%s` \
		WHERE `permanent` = 0 \
		AND %d <= `timestamp` \
		AND `timestamp` <= %d;",
		szVaultName, iStart, iEnd);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_prune(): %s", __SQLVAULT_ERROR);
	}
	else if(!(iReturn = SQL_AffectedRows(hQuery)))
	{
		iReturn = 1;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Updates the timestamp for a key in a vault
 * 
 * @param		hVault - The vault to update the key in
 * @param		szKey - The key to update the timestamp for
 * @param		iTimeStamp - The timestamp to set for the vault (optional, default is -1)
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Use -1 for timestamp to update with the current timestamp
 * 
 * @note		Use "*" for the key to touch all entries.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_touch(SQLVault:hVault, szKey[], iTimeStamp = -1)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_touch() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	if(iTimeStamp < 0)
	{
		iTimeStamp = get_systime();
	}
	
	new Handle:hQuery;
	
	if(equal(szKey, "*"))
	{
		hQuery = SQL_PrepareQuery(hConnection,\
			"UPDATE `%s` \
			SET `timestamp` = %d;",
			szVaultName, iTimeStamp);
	}
	else
	{
		QuoteString(szKey);
		
		hQuery = SQL_PrepareQuery(hConnection,\
			"UPDATE `%s` \
			SET `timestamp` = %d \
			WHERE `key` = '%s';",
			szVaultName, iTimeStamp, szKey);
		
		UnQuoteString(szKey);
	}
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_touch(): %s", __SQLVAULT_ERROR);
	}
	else if(!(iReturn = SQL_AffectedRows(hQuery)))
	{
		iReturn = 1;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Deletes all entries in a vault
 * 
 * @param		hVault - The vault to delete entries from
 * @param		bSavePermanent - If true, deletes only entries that are not permanent. If false, deletes all entries. (optional, default is false)
 * 
 * @return		Returns total entries deleted (or 1 if empty) on success, 0 on failure.
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_clear(SQLVault:hVault, bool:bSavePermanent = false)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_clear() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"DELETE FROM `%s`%s;",
		szVaultName, bSavePermanent ? " WHERE `permanent` = 0" : "");
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_clear(): %s", __SQLVAULT_ERROR);
	}
	else if(!(iReturn = SQL_AffectedRows(hQuery)))
	{
		iReturn = 1;
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Gets the total number of entries in the vault
 * 
 * @param		hVault - The vault to find the size of
 * 
 * @return		Returns the total number of entries in the vault
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_size(SQLVault:hVault)
{
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_size() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"SELECT COUNT(*) FROM `%s`;",
		szVaultName);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_size(): %s", __SQLVAULT_ERROR);
	}
	else if(SQL_NumResults(hQuery))
	{
		iReturn = SQL_ReadResult(hQuery, 0);
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Reads a vault by key index
 * 
 * @param		hVault - The vault to read from
 * @param		iKeyIndex - The key index to read
 * @param		szKey - The string to hold the key (optional)
 * @param		iKeyLen - The max length of the key buffer (optional)
 * @param		szData - The string to hold the data (optional)
 * @param		iDataLen - The max length of the data buffer (optional)
 * @param		iTimeStamp - The byref variable that holds the timestamp (optional)
 * @param		szWhere - The where condition for selecting specific vault data (optional)
 * @param		szSort - The method to sort the vault data by (optional)
 * 
 * @return		Returns 1 on success, 0 on failure.
 * 
 * @note		Key indexes start at 0 and stop at 1 before the size of the vault (sqlv_size() - 1)
 * 
 * @note		If you want to read all keys in the vault, use sqlv_read_all().
 * 
 * @note		If a vault is changed by setting data, changing timestamps, deleteing, etc. then the key indexes may change.
 * 			Therefore, those type of actions should not be done if more than 1 key is being read.
 * 
 * @note		The where condition is the same as the where clause from MySQL's SELECT statement.
 * 			Do not include "WHERE" inside the where clause.
 * 
 * @note		Sorting the vault data can be done 2 ways:
 * 			1. Pass "asc" to sort in ascending order by the data value
 * 			   Pass "desc" to sort in descending order by the data value
 * 			2. Pass any other string to format the ORDER BY clause from MySQL
 * 			Do not include "ORDER BY" inside the sort string
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_read(SQLVault:hVault, iKeyIndex, szKey[] = "", iKeyLen = 0, szData[] = "", iDataLen = 0, &iTimeStamp = 0, const szWhere[] = "", const szSort[] = "")
{
	if(iKeyLen)
	{
		szKey[0] = 0;
	}
	
	if(iDataLen)
	{
		szData[0] = 0;
	}
	
	iTimeStamp = 0;
	
	new szFixedWhere[256], szFixedSort[256];
	
	if(szWhere[0])
	{
		formatex(szFixedWhere, charsmax(szFixedWhere), " WHERE %s", szWhere);
	}
	
	if(szSort[0])
	{
		if(equali(szSort, "asc") || equali(szSort, "desc"))
		{
			formatex(szFixedSort, charsmax(szFixedSort), " ORDER BY `data` %s", szSort);
		}
		else
		{
			formatex(szFixedSort, charsmax(szFixedSort), " ORDER BY %s", szSort);
		}
	}
	
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_read() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"SELECT `key`, `data`, `timestamp` FROM `%s`%s%s LIMIT %d, 1;",
		szVaultName, iKeyIndex, szFixedWhere, szFixedSort);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_read(): %s", __SQLVAULT_ERROR);
	}
	else if(SQL_NumResults(hQuery))
	{
		iReturn = 1;
		
		if(iKeyLen)
		{
			SQL_ReadResult(hQuery, 0, szKey, iKeyLen);
		}
		
		if(iDataLen)
		{
			SQL_ReadResult(hQuery, 1, szData, iDataLen);
		}
		
		iTimeStamp = SQL_ReadResult(hQuery, 2);
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Reads all of the vault data into a cell array
 * 
 * @param		hVault - The vault to read from
 * @param		aVaultData - The cell array to hold the data
 * @param		szWhere - The where condition for selecting specific vault data (optional)
 * @param		szSort - The method to sort the vault data by (optional)
 * 
 * @return		Returns the total number of vault entries
 * 
 * @note		The where condition is the same as the where clause from MySQL's SELECT statement.
 * 			Do not include "WHERE" inside the where clause.
 * 
 * @note		Sorting the vault data can be done 2 ways:
 * 			1. Pass "asc" to sort in ascending order by the data value
 * 			   Pass "desc" to sort in descending order by the data value
 * 			2. Pass any other string to format the ORDER BY clause from MySQL
 * 			Do not include "ORDER BY" inside the sort string
 * 
 * @note		The cell array contains arrays that correspond to the SQLVaultEntry enum
 * 			
 * @note		Example:
 * 			
 * 			new Array:aVaultData;
 * 			new iVaultKeys = sqlv_read_all(hVault, aVaultData);
 * 			
 * 			new eVaultData[SQLVaultEntry];
 * 			
 * 			for(new i = 0; i < iVaultKeys; i++)
 * 			{
 * 				ArrayGetArray(aVaultData, i, eVaultData);
 * 				
 * 				eVaultData[SQLV_Key] = key
 * 				eVaultData[SQLV_Data] = data
 * 				eVaultData[SQLV_TimeStamp] = timestamp
 * 			}
 * 			
 * 			ArrayDestroy(aVaultData);
 * 
 * @note		The cell array should not be created.
 * 			It is auto-created in the function.
 * 			If the cell array already contains a handle, it is destroyed first.
 * 
 * @note		The cell array needs to be destroyed after being used
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_read_all(SQLVault:hVault, &Array:aVaultData, const szWhere[] = "", const szSort[] = "")
{
	if(aVaultData != Invalid_Array)
	{
		ArrayDestroy(aVaultData);
	}
	
	aVaultData = ArrayCreate(SQLVaultEntry);
	
	new szFixedWhere[256], szFixedSort[256];
	
	if(szWhere[0])
	{
		formatex(szFixedWhere, charsmax(szFixedWhere), " WHERE %s", szWhere);
	}
	
	if(szSort[0])
	{
		if(equali(szSort, "asc") || equali(szSort, "desc"))
		{
			formatex(szFixedSort, charsmax(szFixedSort), " ORDER BY `data` %s", szSort);
		}
		else
		{
			formatex(szFixedSort, charsmax(szFixedSort), " ORDER BY %s", szSort);
		}
	}
	
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_read_all() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"SELECT `key`, `data`, `timestamp` FROM `%s`%s%s;",
		szVaultName);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_read_all(): %s", __SQLVAULT_ERROR);
	}
	else if((iReturn = SQL_NumResults(hQuery)))
	{
		new eVaultData[SQLVaultEntry];
		
		while(SQL_MoreResults(hQuery))
		{
			SQL_ReadResult(hQuery, 0, eVaultData[SQLV_Key], charsmax(eVaultData[SQLV_Key]));
			SQL_ReadResult(hQuery, 1, eVaultData[SQLV_Data], charsmax(eVaultData[SQLV_Data]));
			eVaultData[SQLV_TimeStamp] = SQL_ReadResult(hQuery, 2);
			
			ArrayPushArray(aVaultData, eVaultData);
			
			SQL_NextRow(hQuery);
		}
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Reads a set of the vault data into an array
 * 
 * @param		hVault - The vault to read from
 * @param		eOutputData - The array to store all of the selected set
 * @param		iOutputSize - The size of the set to select
 * @param		iStart - The offset of the vault to start at
 * @param		szWhere - The where condition for selecting specific vault data (optional)
 * @param		szSort - The method to sort the vault data by (optional)
 * 
 * @return		Returns the total number of vault entries
 * 
 * @note		The where condition is the same as the where clause from MySQL's SELECT statement.
 * 			Do not include "WHERE" inside the where clause.
 * 
 * @note		Sorting the vault data can be done 2 ways:
 * 			1. Pass "asc" to sort in ascending order by the data value
 * 			   Pass "desc" to sort in descending order by the data value
 * 			2. Pass any other string to format the ORDER BY clause from MySQL
 * 			Do not include "ORDER BY" inside the sort string
 * 			
 * @note		Example for grabbing top entries:
 * 			
 * 			new eVaultData[10][SQLVaultEntry];
 * 			new iVaultKeys = sqlv_read_set(hVault, eVaultData, sizeof(eVaultData), _, _, "desc");
 * 			
 * 			for(new i = 0; i < iVaultKeys; i++)
 * 			{
 * 				eVaultData[i][SQLV_Key] = key
 * 				eVaultData[i][SQLV_Data] = data
 * 				eVaultData[i][SQLV_TimeStamp] = timestamp
 * 			}
 * 
 */
SQLVAULT_FUNC_ATTRIB sqlv_read_set(SQLVault:hVault, eOutputData[][SQLVaultEntry], iOutputSize, iStart = 0, const szWhere[] = "", const szSort[] = "")
{
	new szFixedWhere[256], szFixedSort[256];
	
	if(szWhere[0])
	{
		formatex(szFixedWhere, charsmax(szFixedWhere), " WHERE %s", szWhere);
	}
	
	if(szSort[0])
	{
		if(equali(szSort, "asc") || equali(szSort, "desc"))
		{
			formatex(szFixedSort, charsmax(szFixedSort), " ORDER BY `data` %s", szSort);
		}
		else
		{
			formatex(szFixedSort, charsmax(szFixedSort), " ORDER BY %s", szSort);
		}
	}
	
	if(hVault == Invalid_SQLVault)
	{
		return 0;
	}
	
	new Handle:hTuple;
	TrieGetCell(Trie:hVault, "tuple", hTuple);
	
	if(hTuple == Empty_Handle)
	{
		return 0;
	}
	
	new Handle:hConnection, bool:bNewConnection = false;
	
	if(!TrieGetCell(Trie:hVault, "connection", hConnection))
	{
		hConnection = SQL_Connect(hTuple, __SQLVAULT_ERRCODE, __SQLVAULT_ERROR, 127);
		
		if(hConnection == Empty_Handle)
		{
			log_amx("Connection failed in sqlv_read_set() (%d): %s", __SQLVAULT_ERRCODE, __SQLVAULT_ERROR);
			
			return 0;
		}
		
		bNewConnection = true;
	}
	
	new szVaultName[32];
	TrieGetString(Trie:hVault, "vaultname", szVaultName, charsmax(szVaultName));
	
	new Handle:hQuery = SQL_PrepareQuery(hConnection,\
		"SELECT `key`, `data`, `timestamp` FROM `%s`%s%s LIMIT %d, %d;",
		szVaultName, szFixedWhere, szFixedSort, iStart, iOutputSize);
	
	new iReturn = 0;
	
	if(!SQL_Execute(hQuery))
	{
		SQL_QueryError(hQuery, __SQLVAULT_ERROR, charsmax(__SQLVAULT_ERROR));
		log_amx("Error in sqlv_read_set(): %s", __SQLVAULT_ERROR);
	}
	else if(SQL_NumResults(hQuery))
	{
		while(iReturn < iOutputSize && SQL_MoreResults(hQuery))
		{
			SQL_ReadResult(hQuery, 0, eOutputData[iReturn][SQLV_Key], charsmax(eOutputData[][SQLV_Key]));
			SQL_ReadResult(hQuery, 1, eOutputData[iReturn][SQLV_Data], charsmax(eOutputData[][SQLV_Data]));
			eOutputData[iReturn][SQLV_TimeStamp] = SQL_ReadResult(hQuery, 2);
			
			iReturn++;
			
			SQL_NextRow(hQuery);
		}
	}
	
	SQL_FreeHandle(hQuery);
	
	if(bNewConnection)
	{
		SQL_FreeHandle(hConnection);
	}
	
	return iReturn;
}

/*
 * Makes a string safe to be held in the vault
 * 
 * @param		szString - The string to be made safe
 * 
 * @return		Returns the length of the string
 * 
 * @note		This overwrites the string's contents, so constants cannot be used.
 * 
 */
SQLVAULT_FUNC_ATTRIB QuoteString(szString[], cRemoveChar = ''')
{
	new i, cChar;
	
	while((cChar = szString[i]))
	{
		if(cChar == cRemoveChar)
		{
			szString[i] = 30;
		}
		
		i++;
	}
	
	return i;
}

/*
 * Restores the strings original state after being used by QuoteString()
 * 
 * @param		szString - The string to be restored
 * 
 * @return		Returns the length of the string
 * 
 * @note		This overwrites the string's contents, so constants cannot be used.
 * 
 */
SQLVAULT_FUNC_ATTRIB UnQuoteString(szString[], cRemoveChar = ''')
{
	new i, cChar;
	
	while((cChar = szString[i]))
	{
		if(cChar == 30)
		{
			szString[i] = cRemoveChar;
		}
		
		i++;
	}
	
	return i;
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang11274\\ f0\\ fs16 \n\\ par }
*/
РЕКЛАМИРАЙ ПРИ НАС!
AMXX-BG.INFO
КАК ДА ИЗПОЛЗВАМ
Добави в началото на .sma файла:
#include <sqlvault>
1. Изтегли
Свали файла от бутона по-горе
2. Копирай
Постави в scripting/include/
3. Включи
Добави #include директивата
4. Компилирай
Използвай amxxpc или scripting/compile.exe