From f302de6dd32fbf3974d93e48ab1ff6942afb92f1 Mon Sep 17 00:00:00 2001 From: MarkLee131 Date: Sun, 29 Mar 2026 03:09:38 +0800 Subject: [PATCH 1/4] fixes SetColumnName/SetRowName not removing old name from label map SetColumnName and SetRowName add the new name to the internal label map but do not remove the old name. After renaming, the old name still resolves via GetColumnIdx/GetRowIdx, which can cause silent data misdirection when the old name is used after a rename. Remove the old name from the map before inserting the new one. Add test104 to verify old names are properly cleaned up. --- CMakeLists.txt | 1 + src/rapidcsv.h | 16 +++++++++++++ tests/test104.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 tests/test104.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cae4c48..4d77232 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,6 +193,7 @@ if(RAPIDCSV_BUILD_TESTS) endif() add_unit_test(test102) add_unit_test(test103) + add_unit_test(test104) # perf tests add_perf_test(ptest001) diff --git a/src/rapidcsv.h b/src/rapidcsv.h index 1d98b4e..4987d58 100644 --- a/src/rapidcsv.h +++ b/src/rapidcsv.h @@ -1448,6 +1448,14 @@ namespace rapidcsv } const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + + // remove old name from map before adding new one + const size_t nameRowIdx = static_cast(mLabelParams.mColumnNameIdx); + if ((nameRowIdx < mData.size()) && (dataColumnIdx < mData.at(nameRowIdx).size())) + { + const std::string oldName = mData.at(nameRowIdx).at(dataColumnIdx); + mColumnNames.erase(oldName); + } mColumnNames[pColumnName] = dataColumnIdx; // increase table size if necessary: @@ -1505,6 +1513,14 @@ namespace rapidcsv void SetRowName(size_t pRowIdx, const std::string& pRowName) { const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + + // remove old name from map before adding new one + if ((mLabelParams.mRowNameIdx >= 0) && (dataRowIdx < mData.size()) && + (static_cast(mLabelParams.mRowNameIdx) < mData.at(dataRowIdx).size())) + { + const std::string oldName = mData.at(dataRowIdx).at(static_cast(mLabelParams.mRowNameIdx)); + mRowNames.erase(oldName); + } mRowNames[pRowName] = dataRowIdx; if (mLabelParams.mRowNameIdx < 0) { diff --git a/tests/test104.cpp b/tests/test104.cpp new file mode 100644 index 0000000..de22c84 --- /dev/null +++ b/tests/test104.cpp @@ -0,0 +1,61 @@ +// test104.cpp - SetColumnName / SetRowName stale label cleanup + +#include +#include "unittest.h" + +int main() +{ + int rv = 0; + + std::string csv = + "name,value\n" + "row1,100\n" + "row2,200\n" + ; + + std::string path = unittest::TempPath(); + unittest::WriteFile(path, csv); + + try + { + // Test 1: SetColumnName removes old name from map + { + rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0)); + + unittest::ExpectEqual(int, doc.GetColumnIdx("value"), 0); + doc.SetColumnName(0, "price"); + unittest::ExpectEqual(int, doc.GetColumnIdx("price"), 0); + unittest::ExpectEqual(int, doc.GetColumnIdx("value"), -1); + } + + // Test 2: SetRowName removes old name from map + { + rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0)); + + unittest::ExpectEqual(int, doc.GetRowIdx("row1"), 0); + doc.SetRowName(0, "item1"); + unittest::ExpectEqual(int, doc.GetRowIdx("item1"), 0); + unittest::ExpectEqual(int, doc.GetRowIdx("row1"), -1); + } + + // Test 3: Data access by new name works correctly + { + rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0)); + + doc.SetColumnName(0, "price"); + unittest::ExpectEqual(std::string, doc.GetCell("price", "row1"), "100"); + + doc.SetRowName(0, "item1"); + unittest::ExpectEqual(std::string, doc.GetCell("price", "item1"), "100"); + } + } + catch (const std::exception& ex) + { + std::cout << ex.what() << std::endl; + rv = 1; + } + + unittest::DeleteFile(path); + + return rv; +} From 617d9ed611ee0628117243dc55b25edc1c97b8c6 Mon Sep 17 00:00:00 2001 From: Kristofer Berggren Date: Sat, 4 Apr 2026 14:04:35 +0800 Subject: [PATCH 2/4] rename test104 -> test105 to prepare for master merge --- CMakeLists.txt | 2 +- tests/{test104.cpp => test105.cpp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{test104.cpp => test105.cpp} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d77232..a5dda16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,7 @@ if(RAPIDCSV_BUILD_TESTS) endif() add_unit_test(test102) add_unit_test(test103) - add_unit_test(test104) + add_unit_test(test105) # perf tests add_perf_test(ptest001) diff --git a/tests/test104.cpp b/tests/test105.cpp similarity index 100% rename from tests/test104.cpp rename to tests/test105.cpp From a1b0d03ae32c10c80e1d10b7238224248c98d242 Mon Sep 17 00:00:00 2001 From: Kristofer Berggren Date: Sat, 4 Apr 2026 14:06:51 +0800 Subject: [PATCH 3/4] tidy up test105 file header --- tests/test105.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test105.cpp b/tests/test105.cpp index de22c84..642eabc 100644 --- a/tests/test105.cpp +++ b/tests/test105.cpp @@ -1,4 +1,4 @@ -// test104.cpp - SetColumnName / SetRowName stale label cleanup +// test105.cpp - SetColumnName / SetRowName stale label cleanup #include #include "unittest.h" From 0baf4a07253c90626cfc56eeab166d45a19df72e Mon Sep 17 00:00:00 2001 From: Kristofer Berggren Date: Sat, 4 Apr 2026 14:10:48 +0800 Subject: [PATCH 4/4] bump version --- src/rapidcsv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rapidcsv.h b/src/rapidcsv.h index 6c307e1..601624f 100644 --- a/src/rapidcsv.h +++ b/src/rapidcsv.h @@ -2,7 +2,7 @@ * rapidcsv.h * * URL: https://github.com/d99kris/rapidcsv - * Version: 8.93 + * Version: 8.94 * * Copyright (C) 2017-2026 Kristofer Berggren * All rights reserved.