@@ -59,79 +59,17 @@ func NewInTuple(left sql.Expression, right sql.Expression) *InTuple {
5959 return & InTuple {BinaryExpressionStub {left , right }}
6060}
6161
62- // validateAndEvalRightTuple will evaluate the right tuple, check if leftType and the right Tuple are comparable,
63- // determine what type to use to compare the two sides, and indicate if right Tuple contains any NULL elements.
64- // Returns
65- // - slice of the evaluated elements
66- // - sql.Type to convert elements to before hashing
67- // - bool indicating if there are null elements
68- // - error
69- func validateAndEvalRightTuple (ctx * sql.Context , lType sql.Type , right Tuple , row sql.Row ) ([]any , sql.Type , bool , error ) {
70- // The NULL handling for IN expressions is tricky. According to
71- // https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_in:
72- // To comply with the SQL standard, IN() returns NULL not only if the expression on the left hand side is NULL, but
73- // also if no match is found in the list and one of the expressions in the list is NULL.
74-
75- // If left is StringType and ANY of the right is NumberType, then we should use Double Type for comparison
76- // If left is NumberType and ANT of the left is StringType, then we should use Double Type for comparison
77- lColCount := types .NumColumns (lType )
78- lIsNumType := types .IsNumber (lType )
79- lIsStrType := types .IsText (lType )
80- var rHasNumType , rHasStrType , rHasNull bool
81- rVals := make ([]any , len (right ))
82- for i , el := range right {
83- rType := el .Type ()
84-
85- // Nested tuples must have the same number of columns
86- rColCount := types .NumColumns (rType )
87- if rColCount != lColCount {
88- return nil , nil , false , sql .ErrInvalidOperandColumns .New (lColCount , types .NumColumns (el .Type ()))
89- }
90-
91- if types .IsNumber (rType ) {
92- rHasNumType = true
93- } else if types .IsText (rType ) {
94- rHasStrType = true
95- }
96-
97- // Null elements are not hashed into the Tuple Map
98- if types .IsNullType (rType ) {
99- rHasNull = true
100- continue
101- }
102- v , err := el .Eval (ctx , row )
103- if err != nil {
104- return nil , nil , false , err
105- }
106- if v == nil {
107- rHasNull = true
108- continue
109- }
110-
111- rVals [i ] = v
112- }
113-
114- var cmpType sql.Type
115- if (lIsStrType && rHasNumType ) || (lIsNumType && rHasStrType ) {
116- cmpType = types .Float64
117- } else if types .IsEnum (lType ) || types .IsSet (lType ) || types .IsText (lType ) {
118- cmpType = lType
119- } else {
120- cmpType = lType
121- for _ , el := range right {
122- cmpType = types .GetCompareType (cmpType , el .Type ())
123- }
124- }
125-
126- return rVals , cmpType , rHasNull , nil
127- }
128-
12962// Eval implements the Expression interface.
13063func (in * InTuple ) Eval (ctx * sql.Context , row sql.Row ) (interface {}, error ) {
13164 lVal , err := in .Left ().Eval (ctx , row )
13265 if err != nil {
13366 return nil , err
13467 }
68+
69+ // The NULL handling for IN expressions is tricky. According to
70+ // https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_in:
71+ // To comply with the SQL standard, IN() returns NULL not only if the expression on the left hand side is NULL, but
72+ // also if no match is found in the list and one of the expressions in the list is NULL.
13573 if lVal == nil {
13674 return nil , nil
13775 }
0 commit comments