// Copyright 2015 by Artem Prilutskiy #include "UserDataStore.h" #include #include #include #include #define GET_ID_FOR_CALL 0 #define GET_CREDENTIALS_FOR_ID 1 UserDataStore::UserDataStore(const char* file) : connection(NULL) { const char* queries[] = { // GET_ID_FOR_CALL "SELECT `ID`" " FROM Users" " WHERE `Call` = ?" " ORDER BY `Priority`" " LIMIT 1", // GET_CREDENTIALS_FOR_ID "SELECT `Call`, `Text`" " FROM Users" " WHERE `ID` = ?", }; connection = mysql_init(NULL); mysql_options(connection, MYSQL_READ_DEFAULT_FILE, realpath(file, NULL)); mysql_real_connect(connection, NULL, NULL, NULL, NULL, 0, NULL, CLIENT_REMEMBER_OPTIONS); my_bool active = true; mysql_options(connection, MYSQL_OPT_RECONNECT, &active); for (size_t index = 0; index < PREPARED_STATEMENT_COUNT; index ++) { const char* query = queries[index]; statements[index] = mysql_stmt_init(connection); mysql_stmt_prepare(statements[index], query, strlen(query)); } const char* error = mysql_error(connection); if ((error != NULL) && (*error != '\0')) syslog(LOG_CRIT, "MySQL error: %s\n", error); } UserDataStore::~UserDataStore() { for (size_t index = 0; index < PREPARED_STATEMENT_COUNT; index ++) mysql_stmt_close(statements[index]); mysql_close(connection); } // Public methods uint32_t UserDataStore::getPrivateIDForCall(const char* call) { uint32_t number; size_t length = strlen(call); return execute(GET_ID_FOR_CALL, 1, 1, MYSQL_TYPE_STRING, call, length, MYSQL_TYPE_LONG, &number) * number; } bool UserDataStore::getCredentialsForID(uint32_t number, char* call, char* text) { return execute(GET_CREDENTIALS_FOR_ID, 1, 2, MYSQL_TYPE_LONG, &number, MYSQL_TYPE_STRING, call, LONG_CALLSIGN_LENGTH + 1, MYSQL_TYPE_STRING, text, SLOW_DATA_TEXT_LENGTH + 1); } // Internals MYSQL_BIND* UserDataStore::bind(int count, va_list* arguments) { MYSQL_BIND* bindings = NULL; if (count > 0) { bindings = (MYSQL_BIND*)calloc(count, sizeof(MYSQL_BIND)); for (int index = 0; index < count; index ++) { int type = va_arg(*arguments, int); bindings[index].buffer_type = (enum_field_types)type; bindings[index].buffer = va_arg(*arguments, void*); if ((type == MYSQL_TYPE_STRING) || (type == MYSQL_TYPE_DATETIME)) { bindings[index].buffer_length = va_arg(*arguments, int); bindings[index].length = &bindings[index].buffer_length; } } } return bindings; } bool UserDataStore::execute(int index, int count1, int count2, ...) { bool result = true; MYSQL_STMT* statement = statements[index]; va_list arguments; va_start(arguments, count2); MYSQL_BIND* parameters = bind(count1, &arguments); MYSQL_BIND* columns = bind(count2, &arguments); va_end(arguments); if ((parameters && mysql_stmt_bind_param(statement, parameters)) || (columns && mysql_stmt_bind_result(statement, columns)) || mysql_stmt_execute(statement) || (columns && mysql_stmt_store_result(statement))) { const char* error = mysql_stmt_error(statement); syslog(LOG_CRIT, "MySQL error while processing statement %d: %s\n", index, error); result = false; } if (result && columns) { result = !mysql_stmt_fetch(statement); mysql_stmt_free_result(statement); } free(columns); free(parameters); return result; }