void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) { const auto SignedIntegerOperand = expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed-operand"); // The standard [bitmask.types] allows some integral types to be implemented // as signed types. Exclude these types from diagnosing for bitwise or(|) and // bitwise and(&). Shifting and complementing such values is still not // allowed. const auto BitmaskType = namedDecl(anyOf( hasName("::std::locale::category"), hasName("::std::ctype_base::mask"), hasName("::std::ios_base::fmtflags"), hasName("::std::ios_base::iostate"), hasName("::std::ios_base::openmode"))); const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType))); // Match binary bitwise operations on signed integer arguments. Finder->addMatcher( binaryOperator( allOf(anyOf(hasOperatorName("^"), hasOperatorName("|"), hasOperatorName("&"), hasOperatorName("^="), hasOperatorName("|="), hasOperatorName("&=")), unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))), hasEitherOperand(SignedIntegerOperand), hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))) .bind("binary-no-sign-interference"), this); // Shifting and complement is not allowed for any signed integer type because // the sign bit may corrupt the result. Finder->addMatcher( binaryOperator( allOf(anyOf(hasOperatorName("<<"), hasOperatorName(">>"), hasOperatorName("<<="), hasOperatorName(">>=")), hasEitherOperand(SignedIntegerOperand), hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger())))) .bind("binary-sign-interference"), this); // Match unary operations on signed integer types. Finder->addMatcher(unaryOperator(allOf(hasOperatorName("~"), hasUnaryOperand(SignedIntegerOperand))) .bind("unary-signed"), this); }
//FIXME: VARBINARY??? void PredicateOperator::setOpType(Type& l, Type& r) { if ( l.colDataType == execplan::CalpontSystemCatalog::DATETIME || l.colDataType == execplan::CalpontSystemCatalog::TIME || l.colDataType == execplan::CalpontSystemCatalog::DATE ) { switch (r.colDataType) { case execplan::CalpontSystemCatalog::CHAR: case execplan::CalpontSystemCatalog::VARCHAR: fOperationType = l; break; case execplan::CalpontSystemCatalog::DATETIME: fOperationType.colDataType = execplan::CalpontSystemCatalog::DATETIME; fOperationType.colWidth = 8; break; case execplan::CalpontSystemCatalog::TIME: fOperationType.colDataType = execplan::CalpontSystemCatalog::TIME; fOperationType.colWidth = 8; break; case execplan::CalpontSystemCatalog::DATE: fOperationType = l; break; default: fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE; fOperationType.colWidth = 8; break; } } else if ( r.colDataType == execplan::CalpontSystemCatalog::DATETIME || r.colDataType == execplan::CalpontSystemCatalog::TIME || r.colDataType == execplan::CalpontSystemCatalog::DATE ) { switch (l.colDataType) { case execplan::CalpontSystemCatalog::CHAR: case execplan::CalpontSystemCatalog::VARCHAR: fOperationType.colDataType = execplan::CalpontSystemCatalog::VARCHAR; fOperationType.colWidth = 255; break; case execplan::CalpontSystemCatalog::DATETIME: fOperationType.colDataType = execplan::CalpontSystemCatalog::DATETIME; fOperationType.colWidth = 8; break; case execplan::CalpontSystemCatalog::TIME: fOperationType.colDataType = execplan::CalpontSystemCatalog::TIME; fOperationType.colWidth = 8; break; case execplan::CalpontSystemCatalog::DATE: fOperationType = r; break; default: fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE; fOperationType.colWidth = 8; break; } } else if (l.colDataType == execplan::CalpontSystemCatalog::DECIMAL || l.colDataType == execplan::CalpontSystemCatalog::UDECIMAL) { switch (r.colDataType) { case execplan::CalpontSystemCatalog::DECIMAL: case execplan::CalpontSystemCatalog::UDECIMAL: { // should following the result type that MySQL gives fOperationType = l; fOperationType.scale = (l.scale > r.scale ? l.scale : r.scale); break; } case execplan::CalpontSystemCatalog::INT: case execplan::CalpontSystemCatalog::MEDINT: case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::BIGINT: case execplan::CalpontSystemCatalog::UINT: case execplan::CalpontSystemCatalog::UMEDINT: case execplan::CalpontSystemCatalog::UTINYINT: case execplan::CalpontSystemCatalog::UBIGINT: fOperationType.colDataType = execplan::CalpontSystemCatalog::DECIMAL; fOperationType.scale = l.scale; fOperationType.colWidth = 8; break; default: fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE; fOperationType.colWidth = 8; } } else if (r.colDataType == execplan::CalpontSystemCatalog::DECIMAL || r.colDataType == execplan::CalpontSystemCatalog::UDECIMAL) { switch (l.colDataType) { case execplan::CalpontSystemCatalog::DECIMAL: case execplan::CalpontSystemCatalog::UDECIMAL: { // should following the result type that MySQL gives based on the following logic? // @NOTE is this trustable? fOperationType = fResultType; break; } case execplan::CalpontSystemCatalog::INT: case execplan::CalpontSystemCatalog::MEDINT: case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::BIGINT: case execplan::CalpontSystemCatalog::UINT: case execplan::CalpontSystemCatalog::UMEDINT: case execplan::CalpontSystemCatalog::UTINYINT: case execplan::CalpontSystemCatalog::UBIGINT: fOperationType.colDataType = execplan::CalpontSystemCatalog::DECIMAL; fOperationType.scale = r.scale; fOperationType.colWidth = 8; break; default: fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE; fOperationType.colWidth = 8; } } // If both sides are unsigned, use UBIGINT as result type, otherwise // "promote" to BIGINT. else if (isUnsigned(l.colDataType) && isUnsigned(r.colDataType)) { fOperationType.colDataType = execplan::CalpontSystemCatalog::UBIGINT; fOperationType.colWidth = 8; } else if ((isSignedInteger(l.colDataType) && isUnsigned(r.colDataType)) || (isUnsigned(l.colDataType) && isSignedInteger(r.colDataType)) || (isSignedInteger(l.colDataType) && isSignedInteger(r.colDataType))) { fOperationType.colDataType = execplan::CalpontSystemCatalog::BIGINT; fOperationType.colWidth = 8; } else if ((l.colDataType == execplan::CalpontSystemCatalog::CHAR || l.colDataType == execplan::CalpontSystemCatalog::VARCHAR || l.colDataType == execplan::CalpontSystemCatalog::TEXT) && (r.colDataType == execplan::CalpontSystemCatalog::CHAR || r.colDataType == execplan::CalpontSystemCatalog::VARCHAR || r.colDataType == execplan::CalpontSystemCatalog::TEXT)) { if ( ( (l.colDataType == execplan::CalpontSystemCatalog::CHAR && l.colWidth <= 8) || (l.colDataType == execplan::CalpontSystemCatalog::VARCHAR && l.colWidth < 8) ) && ( (r.colDataType == execplan::CalpontSystemCatalog::CHAR && r.colWidth <= 8) || (r.colDataType == execplan::CalpontSystemCatalog::VARCHAR && r.colWidth < 8) ) ) { if ( futf8 ) { fOperationType.colDataType = execplan::CalpontSystemCatalog::VARCHAR; fOperationType.colWidth = 255; } else { fOperationType.colDataType = execplan::CalpontSystemCatalog::BIGINT; fOperationType.scale = 0; fOperationType.colWidth = 8; // @bug3532, char[] as network order int for fast comparison. l.colDataType = execplan::CalpontSystemCatalog::STRINT; r.colDataType = execplan::CalpontSystemCatalog::STRINT; } } else { fOperationType.colDataType = execplan::CalpontSystemCatalog::VARCHAR; fOperationType.colWidth = 255; } } else { fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE; fOperationType.colWidth = 8; } }