From 5b9f2a0505c11585873aafb4372e4e9ce73d2891 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Wed, 4 Sep 2019 23:48:37 -0400 Subject: [PATCH] fix for duplicate records being saved. I'm going to continually monitor it, some minor changes might need to be made. The changes are changing to prepared statements for queries --- src/database/AlbumRepository.cpp | 90 +++++++++++++++++++++++------ src/database/ArtistRepository.cpp | 48 ++++++++++++++- src/database/BaseRepository.cpp | 2 + src/database/CoverArtRepository.cpp | 49 +++++++++++++++- src/database/GenreRepository.cpp | 48 ++++++++++++++- src/database/YearRepository.cpp | 46 ++++++++++++++- src/manager/ArtistManager.cpp | 3 + src/manager/SongManager.cpp | 3 + 8 files changed, 265 insertions(+), 24 deletions(-) diff --git a/src/database/AlbumRepository.cpp b/src/database/AlbumRepository.cpp index 01ea4d9..2c35f84 100644 --- a/src/database/AlbumRepository.cpp +++ b/src/database/AlbumRepository.cpp @@ -24,29 +24,45 @@ model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type std::cout << "retrieving album record" << std::endl; std::stringstream qry; auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + + MYSQL_BIND params[1]; + memset(params, 0, sizeof(params)); + qry << "SELECT alb.* FROM Album alb WHERE "; - std::unique_ptr param; + auto titleLength = album.title.size(); switch (filter) { case type::AlbumFilter::id: qry << "alb.AlbumId = " << album.id; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&album.id; + params[0].length = 0; + params[0].is_null = 0; break; case type::AlbumFilter::title: - param = std::make_unique(new char[album.title.size()]); - mysql_real_escape_string(conn, *param, album.title.c_str(), album.title.size()); - qry << "alb.Title = '" << *param << "'"; + qry << "alb.Title = ?"; + + params[0].buffer_type = MYSQL_TYPE_STRING; + params[0].buffer = (char*)album.title.c_str(); + params[0].length = &titleLength; + params[0].is_null = 0; break; default: break; } - qry << " ORDER BY AlbumId DESC LIMIT 1"; + qry << " LIMIT 1"; - const std::string query = qry.str(); - auto results = performMysqlQuery(conn, query); + const auto query = qry.str(); + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); - album = parseRecord(results); + album = parseRecord(stmt); + mysql_stmt_close(stmt); mysql_close(conn); std::cout << "done" << std::endl; @@ -55,14 +71,6 @@ model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type bool database::AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter filter) { - // TODO: continue working on this part. - // Reason: there should be a check to see if an album record already exists - // at the moment there is no check and every time a song is uploaded - // a new album record is created, even for songs that are on the - // same album. This should not happen. There should be one album - // record for songs on the same album. After fixing this, do the - // same for Artist, Genre, and Year records - auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn); @@ -182,8 +190,56 @@ model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results) model::Album database::AlbumRepository::parseRecord(MYSQL_STMT *stmt) { - // TODO: implement this + std::cout << "parsing album record" << std::endl; + mysql_stmt_store_result(stmt); + auto rows = mysql_stmt_num_rows(stmt); + model::Album album; + auto status = 0; + auto time = 0; + auto valAmt = 3; + unsigned long len[valAmt]; + my_bool nullRes[valAmt]; + + while (status == 0) { + if (mysql_stmt_field_count(stmt) > 0) { + auto res = mysql_stmt_result_metadata(stmt); + auto fields = mysql_fetch_fields(res); + auto strLen = 1024; + + MYSQL_BIND val[valAmt]; + memset(val, 0, sizeof(val)); + + char title[strLen]; + + val[0].buffer_type = MYSQL_TYPE_LONG; + val[0].buffer = (char*)&album.id; + val[0].length = &len[0]; + val[0].is_null = &nullRes[0]; + + val[1].buffer_type = MYSQL_TYPE_STRING; + val[1].buffer = (char*)title; + val[1].buffer_length = strLen; + val[1].length = &len[1]; + val[1].is_null = &nullRes[1]; + + val[2].buffer_type = MYSQL_TYPE_LONG; + val[2].buffer = (char*)&album.year; + val[2].length = &len[2]; + val[2].is_null = &nullRes[2]; + + status = mysql_stmt_bind_result(stmt, val); + mysql_stmt_store_result(stmt); + + status = mysql_stmt_fetch(stmt); + + album.title = title; + } + + status = mysql_stmt_next_result(stmt); + } + + std::cout << "done parsing album record" << std::endl; return album; } diff --git a/src/database/ArtistRepository.cpp b/src/database/ArtistRepository.cpp index 3487106..2142c70 100644 --- a/src/database/ArtistRepository.cpp +++ b/src/database/ArtistRepository.cpp @@ -49,9 +49,53 @@ model::Artist database::ArtistRepository::retrieveRecord(model::Artist& artist, bool database::ArtistRepository::doesArtistExist(const model::Artist& artist, type::ArtistFilter filter) { - // TODO: implement this + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + + MYSQL_BIND params[1]; + memset(params, 0, sizeof(params)); + + std::stringstream qry; + qry << "SELECT * FROM Artist WHERE "; + + auto artistLength = artist.artist.size(); + switch (filter) { + case type::ArtistFilter::id: + qry << "ArtistId = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&artist.id; + params[0].length = 0; + params[0].is_null = 0; + break; + case type::ArtistFilter::artist: + qry << "Artist = ?"; + + params[0].buffer_type = MYSQL_TYPE_STRING; + params[0].buffer = (char*)artist.artist.c_str(); + params[0].length = &artistLength; + params[0].is_null = 0; + break; + default: + break; + } + + qry << " LIMIT 1"; + + const auto query = qry.str(); + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); + + std::cout << "the query has been performed" << std::endl; + + mysql_stmt_store_result(stmt); + auto rowCount = mysql_stmt_num_rows(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); - return false; + return (rowCount > 0) ? true : false; } void database::ArtistRepository::saveRecord(const model::Artist& artist) diff --git a/src/database/BaseRepository.cpp b/src/database/BaseRepository.cpp index a0aba2d..74ea18e 100644 --- a/src/database/BaseRepository.cpp +++ b/src/database/BaseRepository.cpp @@ -70,4 +70,6 @@ void database::BaseRepository::initializeDetails(const model::BinaryPath& bConf) details.server = databaseConfig["server"].get(); details.username = databaseConfig["username"].get(); details.password = databaseConfig["password"].get(); + + std::cout << "retrieved database details" << std::endl; } diff --git a/src/database/CoverArtRepository.cpp b/src/database/CoverArtRepository.cpp index eb1a4fa..cdd3eeb 100644 --- a/src/database/CoverArtRepository.cpp +++ b/src/database/CoverArtRepository.cpp @@ -48,8 +48,53 @@ model::Cover database::CoverArtRepository::retrieveRecord(model::Cover& cov, typ bool database::CoverArtRepository::doesCoverArtExist(const model::Cover& cover, type::CoverFilter filter) { - // TODO: implement this - return false; + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); + + MYSQL_BIND params[1]; + memset(params, 0, sizeof(params)); + + std::stringstream qry; + qry << "SELECT * FROM CoverArt WHERE "; + + auto titleLength = cover.songTitle.size(); + switch (filter) { + case type::CoverFilter::id: + qry << "CoverArtId = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&cover.id; + params[0].length = 0; + params[0].is_null = 0; + break; + case type::CoverFilter::songTitle: + qry << "SongTitle = ?"; + + params[0].buffer_type = MYSQL_TYPE_STRING; + params[0].buffer = (char*)cover.songTitle.c_str(); + params[0].length = &titleLength; + params[0].is_null = 0; + break; + default: + break; + } + + qry << " LIMIT 1"; + + const auto query = qry.str(); + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); + + std::cout << "the query has been performed" << std::endl; + + mysql_stmt_store_result(stmt); + auto rowCount = mysql_stmt_num_rows(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + return (rowCount > 0) ? true : false; } void database::CoverArtRepository::deleteRecord(const model::Cover& cov) diff --git a/src/database/GenreRepository.cpp b/src/database/GenreRepository.cpp index 45cec27..a783bae 100644 --- a/src/database/GenreRepository.cpp +++ b/src/database/GenreRepository.cpp @@ -47,9 +47,53 @@ model::Genre database::GenreRepository::retrieveRecord(model::Genre& genre, type bool database::GenreRepository::doesGenreExist(const model::Genre& genre, type::GenreFilter filter) { - // TODO: implement this + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); - return false; + std::stringstream qry; + qry << "SELECT * FROM Genre WHERE "; + + MYSQL_BIND params[1]; + memset(params, 0, sizeof(params)); + + auto categoryLength = genre.category.size(); + switch (filter) { + case type::GenreFilter::id: + qry << "GenreId = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&genre.id; + params[0].length = 0; + params[0].is_null = 0; + break; + case type::GenreFilter::category: + qry << "Category = ?"; + + params[0].buffer_type = MYSQL_TYPE_STRING; + params[0].buffer = (char*)genre.category.c_str(); + params[0].length = &categoryLength; + params[0].is_null = 0; + break; + default: + break; + } + + qry << " LIMIT 1"; + + const auto query = qry.str(); + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); + + std::cout << "the query has been performed" << std::endl; + + mysql_stmt_store_result(stmt); + auto rowCount = mysql_stmt_num_rows(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + return (rowCount > 0) ? true : false; } void database::GenreRepository::saveRecord(const model::Genre& genre) diff --git a/src/database/YearRepository.cpp b/src/database/YearRepository.cpp index 0c20e9a..4cd8676 100644 --- a/src/database/YearRepository.cpp +++ b/src/database/YearRepository.cpp @@ -47,8 +47,52 @@ model::Year database::YearRepository::retrieveRecord(model::Year& year, type::Ye bool database::YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter) { // TODO: implement this + auto conn = setupMysqlConnection(); + auto stmt = mysql_stmt_init(conn); - return false; + std::stringstream qry; + qry << "SELECT * FROM Year WHERE "; + + MYSQL_BIND params[1]; + memset(params, 0, sizeof(params)); + + switch (filter) { + case type::YearFilter::id: + qry << "YearId = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&year.id; + params[0].length = 0; + params[0].is_null = 0; + break; + case type::YearFilter::year: + qry << "Year = ?"; + + params[0].buffer_type = MYSQL_TYPE_LONG; + params[0].buffer = (char*)&year.year; + params[0].length = 0; + params[0].is_null = 0; + break; + default: + break; + } + + qry << " LIMIT 1"; + + const auto query = qry.str(); + auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); + status = mysql_stmt_bind_param(stmt, params); + status = mysql_stmt_execute(stmt); + + std::cout << "the query has been performed" << std::endl; + + mysql_stmt_store_result(stmt); + auto rowCount = mysql_stmt_num_rows(stmt); + + mysql_stmt_close(stmt); + mysql_close(conn); + + return (rowCount > 0) ? true : false; } void database::YearRepository::saveRecord(const model::Year& year) diff --git a/src/manager/ArtistManager.cpp b/src/manager/ArtistManager.cpp index e579469..7fb8385 100644 --- a/src/manager/ArtistManager.cpp +++ b/src/manager/ArtistManager.cpp @@ -12,7 +12,10 @@ manager::ArtistManager::ArtistManager(const model::BinaryPath& bConf) model::Artist manager::ArtistManager::retrieveArtist(model::Artist& artist) { + std::cout << "retrieving artist record" << std::endl; database::ArtistRepository artRepo(m_bConf); + std::cout << "initialized artist repo" << std::endl; + std::cout << artist.artist << std::endl; artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist); return artist; diff --git a/src/manager/SongManager.cpp b/src/manager/SongManager.cpp index 1b34100..928efed 100644 --- a/src/manager/SongManager.cpp +++ b/src/manager/SongManager.cpp @@ -143,6 +143,7 @@ void manager::SongManager::saveMisc(model::Song& song) ArtistManager artMgr(m_bConf); auto artist = artMgr.saveArtist(song); artist = artMgr.retrieveArtist(artist); + std::cout << "out" << std::endl; manager::ArtistManager::printArtist(artist); GenreManager gnrMgr(m_bConf); @@ -160,4 +161,6 @@ void manager::SongManager::saveMisc(model::Song& song) song.artistId = artist.id; song.genreId = genre.id; song.yearId = year.id; + + std::cout << "done with miscellaneous database records" << std::endl; }