Skip to content

Commit f302de6

Browse files
committed
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.
1 parent 3aa768a commit f302de6

3 files changed

Lines changed: 78 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ if(RAPIDCSV_BUILD_TESTS)
193193
endif()
194194
add_unit_test(test102)
195195
add_unit_test(test103)
196+
add_unit_test(test104)
196197

197198
# perf tests
198199
add_perf_test(ptest001)

src/rapidcsv.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,14 @@ namespace rapidcsv
14481448
}
14491449

14501450
const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx);
1451+
1452+
// remove old name from map before adding new one
1453+
const size_t nameRowIdx = static_cast<size_t>(mLabelParams.mColumnNameIdx);
1454+
if ((nameRowIdx < mData.size()) && (dataColumnIdx < mData.at(nameRowIdx).size()))
1455+
{
1456+
const std::string oldName = mData.at(nameRowIdx).at(dataColumnIdx);
1457+
mColumnNames.erase(oldName);
1458+
}
14511459
mColumnNames[pColumnName] = dataColumnIdx;
14521460

14531461
// increase table size if necessary:
@@ -1505,6 +1513,14 @@ namespace rapidcsv
15051513
void SetRowName(size_t pRowIdx, const std::string& pRowName)
15061514
{
15071515
const size_t dataRowIdx = GetDataRowIndex(pRowIdx);
1516+
1517+
// remove old name from map before adding new one
1518+
if ((mLabelParams.mRowNameIdx >= 0) && (dataRowIdx < mData.size()) &&
1519+
(static_cast<size_t>(mLabelParams.mRowNameIdx) < mData.at(dataRowIdx).size()))
1520+
{
1521+
const std::string oldName = mData.at(dataRowIdx).at(static_cast<size_t>(mLabelParams.mRowNameIdx));
1522+
mRowNames.erase(oldName);
1523+
}
15081524
mRowNames[pRowName] = dataRowIdx;
15091525
if (mLabelParams.mRowNameIdx < 0)
15101526
{

tests/test104.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// test104.cpp - SetColumnName / SetRowName stale label cleanup
2+
3+
#include <rapidcsv.h>
4+
#include "unittest.h"
5+
6+
int main()
7+
{
8+
int rv = 0;
9+
10+
std::string csv =
11+
"name,value\n"
12+
"row1,100\n"
13+
"row2,200\n"
14+
;
15+
16+
std::string path = unittest::TempPath();
17+
unittest::WriteFile(path, csv);
18+
19+
try
20+
{
21+
// Test 1: SetColumnName removes old name from map
22+
{
23+
rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0));
24+
25+
unittest::ExpectEqual(int, doc.GetColumnIdx("value"), 0);
26+
doc.SetColumnName(0, "price");
27+
unittest::ExpectEqual(int, doc.GetColumnIdx("price"), 0);
28+
unittest::ExpectEqual(int, doc.GetColumnIdx("value"), -1);
29+
}
30+
31+
// Test 2: SetRowName removes old name from map
32+
{
33+
rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0));
34+
35+
unittest::ExpectEqual(int, doc.GetRowIdx("row1"), 0);
36+
doc.SetRowName(0, "item1");
37+
unittest::ExpectEqual(int, doc.GetRowIdx("item1"), 0);
38+
unittest::ExpectEqual(int, doc.GetRowIdx("row1"), -1);
39+
}
40+
41+
// Test 3: Data access by new name works correctly
42+
{
43+
rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0));
44+
45+
doc.SetColumnName(0, "price");
46+
unittest::ExpectEqual(std::string, doc.GetCell<std::string>("price", "row1"), "100");
47+
48+
doc.SetRowName(0, "item1");
49+
unittest::ExpectEqual(std::string, doc.GetCell<std::string>("price", "item1"), "100");
50+
}
51+
}
52+
catch (const std::exception& ex)
53+
{
54+
std::cout << ex.what() << std::endl;
55+
rv = 1;
56+
}
57+
58+
unittest::DeleteFile(path);
59+
60+
return rv;
61+
}

0 commit comments

Comments
 (0)