2828#include < iosfwd>
2929#include < cmath>
3030#include < sstream>
31+ #include < limits>
3132
3233#include " operator.h"
3334#include " parsetree.h"
3435#include " mcs_datatype.h"
36+ #include " exceptclasses.h"
37+ #include " overflow_config.h"
3538
3639namespace messageqcpp
3740{
@@ -40,6 +43,7 @@ class ByteStream;
4043
4144namespace execplan
4245{
46+
4347class ArithmeticOperator : public Operator
4448{
4549 using cscType = execplan::CalpontSystemCatalog::ColType;
@@ -270,21 +274,25 @@ inline void ArithmeticOperator::evaluate(rowgroup::Row& row, bool& isNull, Parse
270274 int128_t result = execute (x, y, isNull);
271275 if (!isNull && (result > MAX_UBIGINT || result < 0 ))
272276 {
273- logging::Message::Args args;
274- std::string func = " <unknown>" ;
275- switch (fOp )
276- {
277- case OP_ADD: func = " \" +\" " ; break ;
278- case OP_SUB: func = " \" -\" " ; break ;
279- case OP_MUL: func = " \" *\" " ; break ;
280- case OP_DIV: func = " \" /\" " ; break ;
281- default : break ;
282- }
283- args.add (func);
284- args.add (static_cast <double >(x));
285- args.add (static_cast <double >(y));
286- unsigned errcode = logging::ERR_FUNC_OUT_OF_RANGE_RESULT;
287- throw logging::IDBExcept (logging::IDBErrorInfo::instance ()->errorMsg (errcode, args), errcode);
277+ if (columnstore::isStrictOverflowMode ())
278+ {
279+ logging::Message::Args args;
280+ std::string func = " <unknown>" ;
281+ switch (fOp )
282+ {
283+ case OP_ADD: func = " \" +\" " ; break ;
284+ case OP_SUB: func = " \" -\" " ; break ;
285+ case OP_MUL: func = " \" *\" " ; break ;
286+ case OP_DIV: func = " \" /\" " ; break ;
287+ default : break ;
288+ }
289+ args.add (func);
290+ args.add (static_cast <double >(x));
291+ args.add (static_cast <double >(y));
292+ unsigned errcode = logging::ERR_FUNC_OUT_OF_RANGE_RESULT;
293+ throw logging::IDBExcept (logging::IDBErrorInfo::instance ()->errorMsg (errcode, args), errcode);
294+ }
295+ isNull = true ;
288296 }
289297 fResult .uintVal = static_cast <uint64_t >(result);
290298 }
@@ -344,11 +352,142 @@ inline result_t ArithmeticOperator::execute(result_t op1, result_t op2, bool& is
344352 }
345353 switch (fOp )
346354 {
347- case OP_ADD: return op1 + op2;
355+ case OP_ADD:
356+ {
357+ // Check for addition overflow
358+ // XXX: __int128 is not signed for some reason.
359+ if constexpr (std::is_signed_v<result_t > || std::is_same<__int128, result_t >::value)
360+ {
361+ if ((op2 > 0 && op1 > std::numeric_limits<result_t >::max () - op2) ||
362+ (op2 < 0 && op1 < std::numeric_limits<result_t >::min () - op2))
363+ {
364+ if (columnstore::isStrictOverflowMode ())
365+ {
366+ // Strict mode: throw exception for out of range
367+ std::ostringstream oss;
368+ oss << " BIGINT value is out of range in addition" ;
369+ throw logging::IDBExcept (oss.str (), logging::ERR_FUNC_OUT_OF_RANGE_RESULT);
370+ }
371+ else
372+ {
373+ // Permissive mode: set null and return clamped value
374+ isNull = true ;
375+ return (op2 > 0 ) ? std::numeric_limits<result_t >::max () : std::numeric_limits<result_t >::min ();
376+ }
377+ }
378+ }
379+ else
380+ {
381+ if (op1 > std::numeric_limits<result_t >::max () - op2)
382+ {
383+ if (columnstore::isStrictOverflowMode ())
384+ {
385+ // Strict mode: throw exception for out of range
386+ std::ostringstream oss;
387+ oss << " BIGINT UNSIGNED value is out of range in addition" ;
388+ throw logging::IDBExcept (oss.str (), logging::ERR_FUNC_OUT_OF_RANGE_RESULT);
389+ }
390+ else
391+ {
392+ // Permissive mode: set null and return max value
393+ isNull = true ;
394+ return std::numeric_limits<result_t >::max ();
395+ }
396+ }
397+ }
398+ return op1 + op2;
399+ }
348400
349- case OP_SUB: return op1 - op2;
401+ case OP_SUB:
402+ {
403+ // Check for subtraction overflow
404+ if constexpr (std::is_signed_v<result_t > || std::is_same<__int128, result_t >::value)
405+ {
406+ if ((op2 < 0 && op1 > std::numeric_limits<result_t >::max () + op2) ||
407+ (op2 > 0 && op1 < std::numeric_limits<result_t >::min () + op2))
408+ {
409+ if (columnstore::isStrictOverflowMode ())
410+ {
411+ // Strict mode: throw exception for out of range
412+ std::ostringstream oss;
413+ oss << " BIGINT value is out of range in subtraction" ;
414+ throw logging::IDBExcept (oss.str (), logging::ERR_FUNC_OUT_OF_RANGE_RESULT);
415+ }
416+ else
417+ {
418+ // Permissive mode: set null and return clamped value
419+ isNull = true ;
420+ return (op2 < 0 ) ? std::numeric_limits<result_t >::max () : std::numeric_limits<result_t >::min ();
421+ }
422+ }
423+ }
424+ else
425+ {
426+ if (op1 < op2)
427+ {
428+ if (columnstore::isStrictOverflowMode ())
429+ {
430+ // Handle underflow - throw exception for out of range
431+ std::ostringstream oss;
432+ oss << " BIGINT UNSIGNED value is out of range in subtraction" ;
433+ throw logging::IDBExcept (oss.str (), logging::ERR_FUNC_OUT_OF_RANGE_RESULT);
434+ }
435+ else
436+ {
437+ isNull = true ;
438+ }
439+ }
440+ }
441+ return op1 - op2;
442+ }
350443
351- case OP_MUL: return op1 * op2;
444+ case OP_MUL:
445+ {
446+ // Check for multiplication overflow
447+ if (op1 != 0 && op2 != 0 )
448+ {
449+ if constexpr (std::is_signed_v<result_t > || std::is_same<__int128, result_t >::value)
450+ {
451+ // For signed types, check both positive and negative overflow
452+ if ((op1 > 0 && op2 > 0 && op1 > std::numeric_limits<result_t >::max () / op2) ||
453+ (op1 < 0 && op2 < 0 && op1 < std::numeric_limits<result_t >::max () / op2) ||
454+ (op1 > 0 && op2 < 0 && op2 < std::numeric_limits<result_t >::min () / op1) ||
455+ (op1 < 0 && op2 > 0 && op1 < std::numeric_limits<result_t >::min () / op2))
456+ {
457+ if (columnstore::isStrictOverflowMode ())
458+ {
459+ // Handle overflow - throw exception for out of range
460+ std::ostringstream oss;
461+ oss << " BIGINT value is out of range in multiplication" ;
462+ throw logging::IDBExcept (oss.str (), logging::ERR_FUNC_OUT_OF_RANGE_RESULT);
463+ }
464+ else
465+ {
466+ isNull = true ;
467+ }
468+ }
469+ }
470+ else
471+ {
472+ // For unsigned types
473+ if (op1 > std::numeric_limits<result_t >::max () / op2)
474+ {
475+ if (columnstore::isStrictOverflowMode ())
476+ {
477+ // Handle overflow - throw exception for out of range
478+ std::ostringstream oss;
479+ oss << " BIGINT UNSIGNED value is out of range in multiplication" ;
480+ throw logging::IDBExcept (oss.str (), logging::ERR_FUNC_OUT_OF_RANGE_RESULT);
481+ }
482+ else
483+ {
484+ isNull = true ;
485+ }
486+ }
487+ }
488+ }
489+ return op1 * op2;
490+ }
352491
353492 case OP_DIV:
354493 if (op2)
0 commit comments