Skip to content

Commit fbf08cd

Browse files
Unit tests for decimalPlaceDec and ArithmeticOperator
1 parent 18e9530 commit fbf08cd

File tree

3 files changed

+289
-2
lines changed

3 files changed

+289
-2
lines changed

tests/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ if(WITH_UNITTESTS)
6969
columnstore_link(compression_tests ${ENGINE_LDFLAGS} ${GTEST_LIBRARIES} ${ENGINE_WRITE_LIBS})
7070
gtest_add_tests(TARGET compression_tests TEST_PREFIX columnstore:)
7171

72+
add_executable(arithmetic_tests arithmeticoperator-tests.cpp)
73+
add_dependencies(arithmetic_tests googletest)
74+
columnstore_link(arithmetic_tests ${ENGINE_LDFLAGS} ${GTEST_LIBRARIES} ${ENGINE_WRITE_LIBS})
75+
gtest_add_tests(TARGET arithmetic_tests TEST_PREFIX columnstore:)
76+
7277
add_executable(column_scan_filter_tests primitives_column_scan_and_filter.cpp)
7378
target_compile_options(column_scan_filter_tests PRIVATE -Wno-error -Wno-sign-compare)
7479
add_dependencies(column_scan_filter_tests googletest)

tests/arithmeticoperator-tests.cpp

Lines changed: 200 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,207 @@
1616
MA 02110-1301, USA. */
1717

1818
#include <gtest/gtest.h> // googletest header file
19-
#include "mcs_basic_types.h"
19+
#include "arithmeticoperator.h"
20+
#include "exceptclasses.h"
21+
#include "constantcolumn.h"
22+
#include "parsetree.h"
23+
#include "rowgroup.h"
24+
#include <limits>
25+
#include <memory>
2026

21-
// using CSCDataType = execplan::CalpontSystemCatalog::ColDataType;
27+
using namespace execplan;
28+
29+
class ArithmeticOperatorOverflowTest : public ::testing::Test
30+
{
31+
protected:
32+
void SetUp() override
33+
{
34+
// Create a simple row for testing
35+
row.initToNull();
36+
}
37+
38+
rowgroup::Row row;
39+
};
40+
41+
// Test ArithmeticOperator overflow handling through public interface
42+
TEST_F(ArithmeticOperatorOverflowTest, SignedAdditionOverflow)
43+
{
44+
ArithmeticOperator op("+");
45+
CalpontSystemCatalog::ColType colType;
46+
colType.colDataType = CalpontSystemCatalog::BIGINT;
47+
colType.colWidth = 8;
48+
op.operationType(colType);
49+
50+
// Create constant columns with overflow values (heap allocated for ParseTree)
51+
auto left =
52+
new ConstantColumn(static_cast<int64_t>(std::numeric_limits<int64_t>::max()), ConstantColumn::NUM);
53+
auto right = new ConstantColumn(static_cast<int64_t>(1), ConstantColumn::NUM);
54+
55+
ParseTree leftTree(left);
56+
ParseTree rightTree(right);
57+
58+
bool isNull = false;
59+
60+
// Should throw IDBExcept with ERR_FUNC_OUT_OF_RANGE_RESULT
61+
EXPECT_THROW({ op.getIntVal(row, isNull, &leftTree, &rightTree); }, logging::IDBExcept);
62+
}
63+
64+
TEST_F(ArithmeticOperatorOverflowTest, SignedSubtractionUnderflow)
65+
{
66+
ArithmeticOperator op("-");
67+
CalpontSystemCatalog::ColType colType;
68+
colType.colDataType = CalpontSystemCatalog::BIGINT;
69+
colType.colWidth = 8;
70+
op.operationType(colType);
71+
72+
// Create constant columns with underflow values (heap allocated for ParseTree)
73+
auto left =
74+
new ConstantColumn(static_cast<int64_t>(std::numeric_limits<int64_t>::min()), ConstantColumn::NUM);
75+
auto right = new ConstantColumn(static_cast<int64_t>(1), ConstantColumn::NUM);
76+
77+
ParseTree leftTree(left);
78+
ParseTree rightTree(right);
79+
80+
bool isNull = false;
81+
82+
// Should throw IDBExcept with ERR_FUNC_OUT_OF_RANGE_RESULT
83+
EXPECT_THROW({ op.getIntVal(row, isNull, &leftTree, &rightTree); }, logging::IDBExcept);
84+
}
85+
86+
TEST_F(ArithmeticOperatorOverflowTest, SignedMultiplicationOverflow)
87+
{
88+
ArithmeticOperator op("*");
89+
CalpontSystemCatalog::ColType colType;
90+
colType.colDataType = CalpontSystemCatalog::BIGINT;
91+
colType.colWidth = 8;
92+
op.operationType(colType);
93+
94+
// Create constant columns with overflow values (heap allocated for ParseTree)
95+
auto left = new ConstantColumn(static_cast<int64_t>(16000000000000000LL), ConstantColumn::NUM);
96+
auto right = new ConstantColumn(static_cast<int64_t>(781), ConstantColumn::NUM);
97+
98+
ParseTree leftTree(left);
99+
ParseTree rightTree(right);
100+
101+
bool isNull = false;
102+
103+
// Should throw IDBExcept with ERR_FUNC_OUT_OF_RANGE_RESULT
104+
EXPECT_THROW({ op.getIntVal(row, isNull, &leftTree, &rightTree); }, logging::IDBExcept);
105+
}
106+
107+
TEST_F(ArithmeticOperatorOverflowTest, UnsignedAdditionOverflow)
108+
{
109+
ArithmeticOperator op("+");
110+
CalpontSystemCatalog::ColType colType;
111+
colType.colDataType = CalpontSystemCatalog::UBIGINT;
112+
colType.colWidth = 8;
113+
op.operationType(colType);
114+
115+
// Create constant columns with overflow values (heap allocated for ParseTree)
116+
auto left = new ConstantColumn(static_cast<uint64_t>(std::numeric_limits<uint64_t>::max()),
117+
ConstantColumn::NUM, 0, 0);
118+
auto right = new ConstantColumn(static_cast<uint64_t>(1), ConstantColumn::NUM, 0, 0);
119+
120+
ParseTree leftTree(left);
121+
ParseTree rightTree(right);
122+
123+
bool isNull = false;
124+
125+
// Should throw IDBExcept with ERR_FUNC_OUT_OF_RANGE_RESULT
126+
EXPECT_THROW({ op.getUintVal(row, isNull, &leftTree, &rightTree); }, logging::IDBExcept);
127+
}
128+
129+
TEST_F(ArithmeticOperatorOverflowTest, UnsignedSubtractionUnderflow)
130+
{
131+
ArithmeticOperator op("-");
132+
CalpontSystemCatalog::ColType colType;
133+
colType.colDataType = CalpontSystemCatalog::UBIGINT;
134+
colType.colWidth = 8;
135+
op.operationType(colType);
136+
137+
// Create constant columns with underflow values (heap allocated for ParseTree)
138+
auto left = new ConstantColumn(static_cast<uint64_t>(0), ConstantColumn::NUM, 0, 0);
139+
auto right = new ConstantColumn(static_cast<uint64_t>(1), ConstantColumn::NUM, 0, 0);
140+
141+
ParseTree leftTree(left);
142+
ParseTree rightTree(right);
143+
144+
bool isNull = false;
145+
146+
// Should throw IDBExcept with ERR_FUNC_OUT_OF_RANGE_RESULT
147+
EXPECT_THROW({ op.getUintVal(row, isNull, &leftTree, &rightTree); }, logging::IDBExcept);
148+
}
149+
150+
TEST_F(ArithmeticOperatorOverflowTest, UnsignedMultiplicationOverflow)
151+
{
152+
ArithmeticOperator op("*");
153+
CalpontSystemCatalog::ColType colType;
154+
colType.colDataType = CalpontSystemCatalog::UBIGINT;
155+
colType.colWidth = 8;
156+
op.operationType(colType);
157+
158+
// Create constant columns with overflow values (heap allocated for ParseTree)
159+
auto left = new ConstantColumn(static_cast<uint64_t>(std::numeric_limits<uint64_t>::max()),
160+
ConstantColumn::NUM, 0, 0);
161+
auto right = new ConstantColumn(static_cast<uint64_t>(2), ConstantColumn::NUM, 0, 0);
162+
163+
ParseTree leftTree(left);
164+
ParseTree rightTree(right);
165+
166+
bool isNull = false;
167+
168+
// Should throw IDBExcept with ERR_FUNC_OUT_OF_RANGE_RESULT
169+
EXPECT_THROW({ op.getUintVal(row, isNull, &leftTree, &rightTree); }, logging::IDBExcept);
170+
}
171+
172+
TEST_F(ArithmeticOperatorOverflowTest, ValidOperationsNoThrow)
173+
{
174+
ArithmeticOperator addOp("+");
175+
CalpontSystemCatalog::ColType colType;
176+
colType.colDataType = CalpontSystemCatalog::BIGINT;
177+
colType.colWidth = 8;
178+
addOp.operationType(colType);
179+
180+
// Create constant columns with normal values (heap allocated for ParseTree)
181+
auto left = new ConstantColumn(static_cast<int64_t>(100), ConstantColumn::NUM);
182+
auto right = new ConstantColumn(static_cast<int64_t>(200), ConstantColumn::NUM);
183+
184+
ParseTree leftTree(left);
185+
ParseTree rightTree(right);
186+
187+
bool isNull = false;
188+
189+
// Should not throw and return correct result
190+
EXPECT_NO_THROW({
191+
int64_t result = addOp.getIntVal(row, isNull, &leftTree, &rightTree);
192+
EXPECT_EQ(result, 300LL);
193+
EXPECT_FALSE(isNull);
194+
});
195+
}
196+
197+
TEST_F(ArithmeticOperatorOverflowTest, DivisionByZero)
198+
{
199+
ArithmeticOperator divOp("/");
200+
CalpontSystemCatalog::ColType colType;
201+
colType.colDataType = CalpontSystemCatalog::BIGINT;
202+
colType.colWidth = 8;
203+
divOp.operationType(colType);
204+
205+
// Create constant columns for division by zero (heap allocated for ParseTree)
206+
auto left = new ConstantColumn(static_cast<int64_t>(100), ConstantColumn::NUM);
207+
auto right = new ConstantColumn(static_cast<int64_t>(0), ConstantColumn::NUM);
208+
209+
ParseTree leftTree(left);
210+
ParseTree rightTree(right);
211+
212+
bool isNull = false;
213+
214+
// Division by zero should set isNull to true, not throw
215+
EXPECT_NO_THROW({
216+
divOp.getIntVal(row, isNull, &leftTree, &rightTree);
217+
EXPECT_TRUE(isNull);
218+
});
219+
}
22220

23221
TEST(SimpleCheck, check1)
24222
{

tests/mcs_decimal-tests.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
#include "treenode.h"
2323
#include "mcs_decimal.h"
2424
#include "dataconvert.h"
25+
#include "funchelpers.h"
26+
#include "exceptclasses.h"
2527

2628
using namespace std;
29+
using namespace funcexp;
30+
using namespace funcexp::helpers;
2731

2832
TEST(Decimal, compareCheckInt64)
2933
{
@@ -1595,3 +1599,83 @@ TEST(Decimal, DecimalToStringCheckScale37)
15951599
dec.setTSInt128Value(res);
15961600
EXPECT_EQ(dec.toString(), expected);
15971601
}
1602+
1603+
// Test overflow handling in funchelpers::decimalPlaceDec
1604+
TEST(FuncHelpers, decimalPlaceDecOverflowInt64)
1605+
{
1606+
// Test int64_t overflow during decimal scaling
1607+
// For overflow: p > max/10, so p > 922337203685477580
1608+
int64_t d = 2; // d < s, so scaling will occur
1609+
int64_t p = 922337203685477581LL; // Just above max/10 to trigger overflow
1610+
int8_t s = 5; // Current scale
1611+
1612+
// This should trigger overflow handling in strict mode
1613+
EXPECT_THROW({ decimalPlaceDec(d, p, s); }, logging::IDBExcept);
1614+
}
1615+
1616+
TEST(FuncHelpers, decimalPlaceDecOverflowInt32)
1617+
{
1618+
// Test int32_t overflow during decimal scaling
1619+
// For int32_t overflow: p > INT32_MAX/10, so p > 214748364
1620+
int64_t d = 2; // d < s, so scaling will occur
1621+
int32_t p = 214748365; // Just above INT32_MAX/10 to trigger overflow
1622+
int8_t s = 5; // Current scale
1623+
1624+
// This should trigger overflow handling in strict mode
1625+
EXPECT_THROW({ decimalPlaceDec(d, p, s); }, logging::IDBExcept);
1626+
}
1627+
1628+
TEST(FuncHelpers, decimalPlaceDecOverflowUInt64)
1629+
{
1630+
// Test uint64_t overflow during decimal scaling
1631+
// For uint64_t overflow: p > UINT64_MAX/10, so p > 1844674407370955161
1632+
int64_t d = 2; // d < s, so scaling will occur
1633+
uint64_t p = 1844674407370955162ULL; // Just above UINT64_MAX/10 to trigger overflow
1634+
int8_t s = 5; // Current scale
1635+
1636+
// This should trigger overflow handling in strict mode
1637+
EXPECT_THROW({ decimalPlaceDec(d, p, s); }, logging::IDBExcept);
1638+
}
1639+
1640+
TEST(FuncHelpers, decimalPlaceDecValidOperations)
1641+
{
1642+
// Test normal operations that should not overflow
1643+
// When d < s, scaling occurs
1644+
int64_t d = 2;
1645+
int64_t p = 123;
1646+
int8_t s = 5;
1647+
1648+
EXPECT_NO_THROW({ decimalPlaceDec(d, p, s); });
1649+
1650+
// d=2, s=5: d < s, so s=2, d=2-5=-3, i=3, p=123*10^3=123000
1651+
EXPECT_EQ(p, 123000);
1652+
EXPECT_EQ(s, 2); // New scale = original d
1653+
}
1654+
1655+
TEST(FuncHelpers, decimalPlaceDecNoScaling)
1656+
{
1657+
// Test case where d >= s, so no scaling occurs
1658+
int64_t d = 7;
1659+
int64_t p = 456;
1660+
int8_t s = 5;
1661+
1662+
EXPECT_NO_THROW({ decimalPlaceDec(d, p, s); });
1663+
1664+
// No scaling should occur, d should be set to s
1665+
EXPECT_EQ(p, 456); // p unchanged
1666+
EXPECT_EQ(d, 5); // d set to s
1667+
}
1668+
1669+
TEST(FuncHelpers, decimalPlaceDecNegativeScaling)
1670+
{
1671+
// Test with negative d value
1672+
int64_t d = -2;
1673+
int64_t p = 789;
1674+
int8_t s = 1;
1675+
1676+
EXPECT_NO_THROW({ decimalPlaceDec(d, p, s); });
1677+
1678+
// d=-2, s=1: d < s, so s=-2, d=-2-1=-3, i=3, p=789*10^3=789000
1679+
EXPECT_EQ(p, 789000);
1680+
EXPECT_EQ(s, -2); // New scale = original d
1681+
}

0 commit comments

Comments
 (0)