mirror of
https://github.com/UberGames/rpgxEF.git
synced 2025-02-24 13:01:10 +00:00
- Fixed all errors that occured due to using c++ compiler - changed c++ standart to c++17 - removed lua, added library instead - made all bg_* and q_* file into a shared item project
644 lines
13 KiB
C++
644 lines
13 KiB
C++
|
|
#ifdef SQL
|
|
|
|
#if (defined(_MSC_VER) | defined(__WIN32__))
|
|
#include "windows.h"
|
|
#endif
|
|
|
|
#include "sqlite3.h"
|
|
#include "g_sql.h"
|
|
#include "g_local.h"
|
|
#include "md5.h"
|
|
#include "g_logger.h"
|
|
|
|
static sqlite3 *user_db;
|
|
static sqlite3 *string_db;
|
|
|
|
static qboolean G_Sql_Check_StepReturn(int32_t r) {
|
|
switch(r) {
|
|
case SQLITE_ROW:
|
|
case SQLITE_DONE:
|
|
return qfalse;
|
|
default:
|
|
G_Logger(LL_ERROR, "SQL ERROR: %s\n", sqlite3_errmsg(user_db));
|
|
break;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
static qboolean G_Sql_Check_PrepareReturn(int32_t r) {
|
|
switch(r) {
|
|
case SQLITE_OK:
|
|
return qfalse;
|
|
default:
|
|
G_Logger(LL_ERROR, "SQL ERROR: %s\n", sqlite3_errmsg(user_db));
|
|
break;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
static qboolean G_Sql_Check_BindReturn(int32_t r) {
|
|
switch(r) {
|
|
case SQLITE_OK:
|
|
return qfalse;
|
|
default:
|
|
G_Logger(LL_ERROR, "SQL ERROR: %s\n", sqlite3_errmsg(user_db));
|
|
break;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
static char* G_Sql_Md5(const char* s) {
|
|
char* res = NULL;
|
|
unsigned char sig[16];
|
|
struct MD5Context md5c;
|
|
|
|
MD5Init(&md5c);
|
|
MD5Update(&md5c, (const unsigned char*)s, strlen(s));
|
|
MD5Final(&md5c, sig);
|
|
|
|
res = (char*)malloc(sizeof(char) * MAX_QPATH);
|
|
if(res != NULL) {
|
|
G_LocLogger(LL_DEBUG, "SQL ERROR: was unable to allocate %u byte\n", sizeof(char) * (strlen(s) + 1));
|
|
return NULL;
|
|
}
|
|
|
|
sprintf(res, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
|
sig[0], sig[1], sig[2], sig[3], sig[4], sig[5], sig[6], sig[7],
|
|
sig[8], sig[9], sig[10], sig[11], sig[12], sig[13], sig[14], sig[15] );
|
|
|
|
return res;
|
|
}
|
|
|
|
qboolean G_Sql_CreateStringDB(void) {
|
|
int res = 0;
|
|
sqlite3_stmt* stmt = NULL;
|
|
|
|
res = sqlite3_open(BASEPATH "/db/strings.db", &string_db);
|
|
if(res != SQLITE_OK) {
|
|
G_LocLogger(LL_ERROR, "%s\n", sqlite3_errmsg(string_db));
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(string_db, SQL_ENABLE_FOREIGN_KEY_CONSTRAINTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
sqlite3_close(string_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
sqlite3_close(string_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
res = sqlite3_prepare_v2(string_db, SQL_STRING_CREATE_TABLE, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
sqlite3_close(string_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
sqlite3_close(string_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean G_Sql_CreateUserDB(void) {
|
|
int res = 0;
|
|
sqlite3_stmt* stmt = NULL;
|
|
|
|
res = sqlite3_open(BASEPATH "/db/users.db", &user_db);
|
|
if(res != SQLITE_OK) {
|
|
G_LocLogger(LL_ERROR, "%s\n", sqlite3_errmsg(user_db));
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_ENABLE_FOREIGN_KEY_CONSTRAINTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
sqlite3_close(user_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
sqlite3_close(user_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_CREATEUSERTABLE, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
sqlite3_close(user_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
sqlite3_close(user_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_CREATERIGHTSTABLE, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
sqlite3_close(user_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
sqlite3_close(user_db);
|
|
level.sqlReady = qfalse;
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean G_Sql_Init(void) {
|
|
level.sqlReady = qfalse;
|
|
|
|
if(sql_use.integer == 0) {
|
|
return qtrue;
|
|
}
|
|
|
|
if(G_Sql_CreateUserDB() == qfalse) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(G_Sql_CreateStringDB() == qfalse) {
|
|
return qfalse;
|
|
}
|
|
|
|
G_Logger(LL_ALWAYS, "SQL initialization complete\n");
|
|
|
|
level.sqlReady = qtrue;
|
|
return qtrue;
|
|
}
|
|
|
|
void G_Sql_Shutdown(void) {
|
|
|
|
G_Logger(LL_ALWAYS, "SQL shutdown\n");
|
|
|
|
if(sql_use.integer == 0) {
|
|
return;
|
|
}
|
|
|
|
if(level.sqlReady == qfalse) {
|
|
return;
|
|
}
|
|
|
|
level.sqlReady = qfalse;
|
|
sqlite3_close(user_db);
|
|
sqlite3_close(string_db);
|
|
}
|
|
|
|
qboolean G_Sql_UserDB_Del(const char* username) {
|
|
sqlite3_stmt* stmt = NULL;
|
|
int32_t res = 0;
|
|
int32_t id = -1;
|
|
|
|
if(username == NULL) {
|
|
G_LocLogger(LL_ERROR, "username is NULL\n");
|
|
return qfalse;
|
|
}
|
|
|
|
if(!level.sqlReady) {
|
|
G_LocLogger(LL_ERROR, "SQL is not initialized!\n");
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_GET_UID, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_text(stmt, 1, username, sizeof(username), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(res == SQLITE_ROW) {
|
|
id = sqlite3_column_int(stmt, 0);
|
|
} else if(res == SQLITE_DONE) {
|
|
G_Logger(LL_ALWAYS, "SQL: User \'%s\' not found\n", username);
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
if(id == -1) {
|
|
G_LocLogger(LL_ERROR, "No user %s found\n", username);
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_DELTE_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 1, id);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_DELETE, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_text(stmt, 1, username, sizeof(username), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean G_Sql_UserDB_Add(const char* username, const char* password) {
|
|
sqlite3_stmt* stmt = NULL;
|
|
int32_t res = 0;
|
|
int32_t id = 0;
|
|
char* hashedpw = NULL;
|
|
|
|
if(username == NULL) {
|
|
G_LocLogger(LL_ERROR, "username is NULL\n");
|
|
return qfalse;
|
|
}
|
|
|
|
if(password == NULL) {
|
|
G_LocLogger(LL_ERROR, "password is NULL\n");
|
|
return qfalse;
|
|
}
|
|
|
|
if(!level.sqlReady) {
|
|
G_LocLogger(LL_ERROR, "SQL is not initialized!\n");
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_GET_UID, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_bind_text(stmt, 1, username, sizeof(username), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
if(res == SQLITE_ROW) {
|
|
G_Logger(LL_ALWAYS, "SQL: There already exists a user with username \'%s\'\n", username);
|
|
G_Logger(LL_ALWAYS, "SQL: If you lost your password please contact an admin with access to the database.\n");
|
|
sqlite3_finalize(stmt);
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
hashedpw = G_Sql_Md5(password);
|
|
if(hashedpw == NULL) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_ADD, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_bind_text(stmt, 1, username, sizeof(username), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_bind_text(stmt, 2, hashedpw, sizeof(hashedpw), free);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(hashedpw != NULL) {
|
|
free(hashedpw);
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_GET_UID, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_bind_text(stmt, 1, username, sizeof(username), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
if(res == SQLITE_ROW) {
|
|
id = sqlite3_column_int(stmt, 0);
|
|
} else {
|
|
G_Logger(LL_ALWAYS, "SQL: There already exists a user with username \'%s\'\n", username);
|
|
sqlite3_finalize(stmt);
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_ADD_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_bind_int(stmt, 1, id);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean G_Sql_UserDB_Login(const char *uName, const char *pwd, int clientnum) {
|
|
sqlite3_stmt* stmt = NULL;
|
|
int res, id;
|
|
char *hashedpw;
|
|
|
|
if(!level.sqlReady) {
|
|
G_Printf(S_COLOR_RED "[SQL-Error] SQL is not initialized!\n");
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_LOGIN, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_text(stmt, 1, uName, sizeof(uName), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
hashedpw = G_Sql_Md5(pwd);
|
|
res = sqlite3_bind_text(stmt, 2, hashedpw, sizeof(hashedpw), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(hashedpw != NULL) {
|
|
free(hashedpw);
|
|
}
|
|
|
|
if(res == SQLITE_ROW) {
|
|
id = sqlite3_column_int(stmt, 0);
|
|
level.clients[clientnum].uid = id;
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_CHECK_ADMIN, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
level.clients[clientnum].uid = -1;
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 1, id);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
level.clients[clientnum].uid = -1;
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
level.clients[clientnum].uid = -1;
|
|
return qfalse;
|
|
}
|
|
|
|
if(res == SQLITE_ROW) {
|
|
level.clients[clientnum].LoggedAsAdmin = qtrue;
|
|
} else {
|
|
level.clients[clientnum].uid = -1;
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean G_Sql_UserDB_CheckRight(int uid, int right) {
|
|
sqlite3_stmt *stmt;
|
|
int res;
|
|
long rights;
|
|
|
|
if(!level.sqlReady) {
|
|
G_Printf(S_COLOR_RED "[SQL-Error] SQL is not initialized!\n");
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_GET_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 1, uid);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(res == SQLITE_ROW) {
|
|
rights = (long)sqlite3_column_int64(stmt, 0);
|
|
if(right & right) {
|
|
sqlite3_finalize(stmt);
|
|
return qtrue;
|
|
} else {
|
|
sqlite3_finalize(stmt);
|
|
return qfalse;
|
|
}
|
|
} else {
|
|
sqlite3_finalize(stmt);
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean G_Sql_UserDB_AddRight(int uid, int right) {
|
|
sqlite3_stmt *stmt;
|
|
int res;
|
|
long rights;
|
|
|
|
if(!level.sqlReady) {
|
|
G_Printf(S_COLOR_RED "[SQL-Error] SQL is not initialized!\n");
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_GET_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(res == SQLITE_ROW) {
|
|
rights = (long)sqlite3_column_int64(stmt, 0);
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
rights |= right;
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_MOD_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 1, rights);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 2, uid);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
sqlite3_finalize(stmt);
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean G_Sql_UserDB_RemoveRight(int uid, int right) {
|
|
sqlite3_stmt *stmt;
|
|
int res;
|
|
long rights;
|
|
|
|
if(!level.sqlReady) {
|
|
G_Printf(S_COLOR_RED "[SQL-Error] SQL is not initialized!\n");
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_MOD_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if(res == SQLITE_ROW) {
|
|
rights = (long)sqlite3_column_int64(stmt, 0);
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
sqlite3_finalize(stmt);
|
|
|
|
rights &= right;
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_MOD_RIGHTS, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 1, rights);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_bind_int(stmt, 2, uid);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(G_Sql_Check_StepReturn(res)) {
|
|
return qfalse;
|
|
}
|
|
|
|
sqlite3_finalize(stmt);
|
|
return qtrue;
|
|
}
|
|
|
|
int G_Sql_UserDB_GetUID(const char *uName) {
|
|
sqlite3_stmt *stmt;
|
|
int res;
|
|
int uid;
|
|
|
|
if(!uName || !uName[0] || !level.sqlReady) {
|
|
return -1;
|
|
}
|
|
|
|
res = sqlite3_prepare_v2(user_db, SQL_USER_GET_UID, -1, &stmt, 0);
|
|
if(G_Sql_Check_PrepareReturn(res)) {
|
|
return -1;
|
|
}
|
|
|
|
res = sqlite3_bind_text(stmt, 1, uName, sizeof(uName), SQLITE_STATIC);
|
|
if(G_Sql_Check_BindReturn(res)) {
|
|
return -1;
|
|
}
|
|
|
|
res = sqlite3_step(stmt);
|
|
if(res == SQLITE_ROW) {
|
|
uid = sqlite3_column_int(stmt, 0);
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
sqlite3_finalize(stmt);
|
|
return uid;
|
|
}
|
|
|
|
#endif //SQL
|