From 7d2a3293eca2b1d46d6ba8670d52d7100865fac6 Mon Sep 17 00:00:00 2001 From: pokeeffe-molecula Date: Mon, 10 Apr 2023 10:51:45 -0500 Subject: [PATCH] fixed all the stuff that adding the vector data type broke --- sql3/errors.go | 4 +- sql3/planner/compilecreatemodel.go | 2 +- sql3/planner/expression.go | 19 ++++++ sql3/planner/expressionanalyzercall.go | 21 ++++--- sql3/planner/expressiontypes.go | 79 +++++++++++++++++++---- sql3/planner/inbuiltfunctionsset.go | 87 ++++++++++++++++++++++++++ sql3/test/defs/defs_between.go | 8 +-- sql3/test/defs/defs_inserts.go | 4 +- sql3/test/defs/defs_set_functions.go | 23 ++++--- sql3/test/defs/defs_timequantum.go | 8 +-- 10 files changed, 213 insertions(+), 42 deletions(-) diff --git a/sql3/errors.go b/sql3/errors.go index 0bd85be3f..9db996d0f 100644 --- a/sql3/errors.go +++ b/sql3/errors.go @@ -234,10 +234,10 @@ func NewErrCacheKeyNotFound(key uint64) error { ) } -func NewErrTypeAssignmentIncompatible(line, col int, type1, type2 string) error { +func NewErrTypeAssignmentIncompatible(line, col int, sourceType, targetType string) error { return errors.New( ErrTypeAssignmentIncompatible, - fmt.Sprintf("[%d:%d] an expression of type '%s' cannot be assigned to type '%s'", line, col, type1, type2), + fmt.Sprintf("[%d:%d] an expression of type '%s' cannot be assigned to type '%s'", line, col, sourceType, targetType), ) } diff --git a/sql3/planner/compilecreatemodel.go b/sql3/planner/compilecreatemodel.go index 42bb04e87..1bba4aa93 100644 --- a/sql3/planner/compilecreatemodel.go +++ b/sql3/planner/compilecreatemodel.go @@ -165,7 +165,7 @@ func (p *ExecutionPlanner) analyzeModelOptionExpr(ctx context.Context, optName s if !e.IsLiteral() { return nil, sql3.NewErrInternalf("string array literal expected") } - ok, baseType := typeIsSet(e.DataType()) + ok, baseType := typeIsAssignmentCompatibleWithSet(e.DataType()) if !ok { return nil, sql3.NewErrInternalf("array expression expected") } diff --git a/sql3/planner/expression.go b/sql3/planner/expression.go index d54b9c54b..1d4307749 100644 --- a/sql3/planner/expression.go +++ b/sql3/planner/expression.go @@ -2455,6 +2455,25 @@ func (n *exprArrayLiteralPlanExpression) Evaluate(currentRow []interface{}) (int } switch typ := arrayType.SubscriptType.(type) { + case *parser.DataTypeInt: + result := []int64{} + for _, e := range n.members { + er, err := e.Evaluate(currentRow) + if err != nil { + return nil, err + } + coercedEr, err := coerceValue(e.Type(), &parser.DataTypeInt{}, er, parser.Pos{Line: 0, Column: 0}) + if err != nil { + return nil, err + } + eri, ok := coercedEr.(int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert element result") + } + result = append(result, eri) + } + return result, nil + case *parser.DataTypeID: result := []int64{} for _, e := range n.members { diff --git a/sql3/planner/expressionanalyzercall.go b/sql3/planner/expressionanalyzercall.go index b75c2c8fa..19cde3c6c 100644 --- a/sql3/planner/expressionanalyzercall.go +++ b/sql3/planner/expressionanalyzercall.go @@ -220,14 +220,17 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 2, len(call.Args)) } - ok, baseType := typeIsSet(call.Args[0].DataType()) + // first arg should be assignment compatible with any set type + ok, baseType := typeIsAssignmentCompatibleWithSet(call.Args[0].DataType()) if !ok { return nil, sql3.NewErrSetExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } - if !typesAreComparable(baseType, call.Args[1].DataType()) { - return nil, sql3.NewErrTypesAreNotEquatable(call.Args[1].Pos().Line, call.Args[1].Pos().Column, call.Args[0].DataType().TypeDescription(), call.Args[1].DataType().TypeDescription()) + // second argument should be assignment compatible with the base type + if !typesAreAssignmentCompatible(baseType, call.Args[1].DataType()) { + return nil, sql3.NewErrTypeAssignmentIncompatible(call.Args[1].Pos().Line, call.Args[1].Pos().Column, call.Args[1].DataType().TypeDescription(), baseType.TypeDescription()) } + call.ResultDataType = parser.NewDataTypeBool() case "SETCONTAINSALL": @@ -236,14 +239,14 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars return nil, sql3.NewErrCallParameterCountMismatch(call.Rparen.Line, call.Rparen.Column, call.Name.Name, 2, len(call.Args)) } - // first arg should be set - ok, baseType1 := typeIsSet(call.Args[0].DataType()) + // first arg should be assignment compatible with any set type + ok, baseType1 := typeIsAssignmentCompatibleWithSet(call.Args[0].DataType()) if !ok { return nil, sql3.NewErrSetExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } - // second arg should be set - ok, baseType2 := typeIsSet(call.Args[1].DataType()) + // second arg should be assignment compatible with any set type + ok, baseType2 := typeIsAssignmentCompatibleWithSet(call.Args[1].DataType()) if !ok { return nil, sql3.NewErrSetExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } @@ -261,13 +264,13 @@ func (p *ExecutionPlanner) analyzeCallExpression(ctx context.Context, call *pars } // first arg should be set - ok, baseType1 := typeIsSet(call.Args[0].DataType()) + ok, baseType1 := typeIsAssignmentCompatibleWithSet(call.Args[0].DataType()) if !ok { return nil, sql3.NewErrSetExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } // second arg should be set - ok, baseType2 := typeIsSet(call.Args[1].DataType()) + ok, baseType2 := typeIsAssignmentCompatibleWithSet(call.Args[1].DataType()) if !ok { return nil, sql3.NewErrSetExpressionExpected(call.Args[0].Pos().Line, call.Args[0].Pos().Column) } diff --git a/sql3/planner/expressiontypes.go b/sql3/planner/expressiontypes.go index cea52a895..cbe67c12d 100644 --- a/sql3/planner/expressiontypes.go +++ b/sql3/planner/expressiontypes.go @@ -290,65 +290,105 @@ func typesAreAssignmentCompatible(targetType parser.ExprDataType, sourceType par return false } case *parser.DataTypeStringSet: - switch sourceType.(type) { + switch source := sourceType.(type) { case *parser.DataTypeStringSet: return true + case *parser.DataTypeArray: + switch source.SubscriptType.(type) { + case *parser.DataTypeString: + return true + default: + return false + } default: return false } + case *parser.DataTypeStringSetQuantum: switch source := sourceType.(type) { case *parser.DataTypeStringSetQuantum: return true case *parser.DataTypeStringSet: return true + case *parser.DataTypeArray: + switch source.SubscriptType.(type) { + case *parser.DataTypeString: + return true + default: + return false + } case *parser.DataTypeTuple: // if we are assigning to a time quantum, a tuple is allowed, but members // have to be a timestamp (or coercable to a timestamp) and and stringset + // (or coercable to a string set) if len(source.Members) != 2 { return false } if !typesAreAssignmentCompatible(parser.NewDataTypeTimestamp(), source.Members[0]) { return false } - _, ok = source.Members[1].(*parser.DataTypeStringSet) + ok, baseType := typeIsAssignmentCompatibleWithSet(source.Members[1]) if !ok { return false } + if !typesAreAssignmentCompatible(parser.NewDataTypeString(), baseType) { + return false + } return true default: return false } + case *parser.DataTypeIDSet: - switch sourceType.(type) { + switch st := sourceType.(type) { case *parser.DataTypeIDSet: return true + case *parser.DataTypeArray: + switch st.SubscriptType.(type) { + case *parser.DataTypeInt, *parser.DataTypeID: + return true + default: + return false + } default: return false } + case *parser.DataTypeIDSetQuantum: switch source := sourceType.(type) { case *parser.DataTypeIDSetQuantum: return true case *parser.DataTypeIDSet: return true + case *parser.DataTypeArray: + switch source.SubscriptType.(type) { + case *parser.DataTypeInt, *parser.DataTypeID: + return true + default: + return false + } case *parser.DataTypeTuple: // if we are assigning to a time quantum, a tuple is allowed, but members - // have to be a timestamp (or coercable to a timestamp) and and idset + // have to be a timestamp (or coercable to a timestamp) and and idset (or coercable to) if len(source.Members) != 2 { return false } if !typesAreAssignmentCompatible(parser.NewDataTypeTimestamp(), source.Members[0]) { return false } - _, ok = source.Members[1].(*parser.DataTypeIDSet) + ok, baseType := typeIsAssignmentCompatibleWithSet(source.Members[1]) if !ok { return false } + // make sure the base type matches + if !typesAreAssignmentCompatible(parser.NewDataTypeID(), baseType) { + return false + } return true default: return false } + case *parser.DataTypeDecimal: switch rhs := sourceType.(type) { case *parser.DataTypeDecimal: @@ -480,9 +520,9 @@ func typeIsRange(testType parser.ExprDataType) bool { } } -// returns true if the type is a set type -func typeIsSet(testType parser.ExprDataType) (bool, parser.ExprDataType) { - switch testType.(type) { +// returns true if the type is assignment compatible with a set, and the subscript type +func typeIsAssignmentCompatibleWithSet(testType parser.ExprDataType) (bool, parser.ExprDataType) { + switch tt := testType.(type) { case *parser.DataTypeIDSet: return true, parser.NewDataTypeID() case *parser.DataTypeStringSet: @@ -491,6 +531,13 @@ func typeIsSet(testType parser.ExprDataType) (bool, parser.ExprDataType) { return true, parser.NewDataTypeID() case *parser.DataTypeStringSetQuantum: return true, parser.NewDataTypeString() + case *parser.DataTypeArray: + switch bt := tt.SubscriptType.(type) { + case *parser.DataTypeID, *parser.DataTypeInt, *parser.DataTypeString: + return true, bt + default: + return false, nil + } default: return false, nil } @@ -635,10 +682,14 @@ func typesAreComparable(testTypeL parser.ExprDataType, testTypeR parser.ExprData } case *parser.DataTypeIDSet: - switch testTypeR.(type) { + switch rhs := testTypeR.(type) { case *parser.DataTypeIDSet: return true - + case *parser.DataTypeArray: + switch rhs.SubscriptType.(type) { + case *parser.DataTypeID, *parser.DataTypeInt: + return true + } } case *parser.DataTypeString: @@ -649,10 +700,14 @@ func typesAreComparable(testTypeL parser.ExprDataType, testTypeR parser.ExprData } case *parser.DataTypeStringSet: - switch testTypeR.(type) { + switch rhs := testTypeR.(type) { case *parser.DataTypeStringSet: return true - + case *parser.DataTypeArray: + switch rhs.SubscriptType.(type) { + case *parser.DataTypeString: + return true + } } } diff --git a/sql3/planner/inbuiltfunctionsset.go b/sql3/planner/inbuiltfunctionsset.go index 0d31c9203..877251bff 100644 --- a/sql3/planner/inbuiltfunctionsset.go +++ b/sql3/planner/inbuiltfunctionsset.go @@ -25,6 +25,35 @@ func (n *callPlanExpression) EvaluateSetContains(currentRow []interface{}) (inte if targetSetEval != nil { switch typ := n.args[0].Type().(type) { + case *parser.DataTypeArray: + switch typ.SubscriptType.(type) { + case *parser.DataTypeString: + targetSet, ok := targetSetEval.([]string) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + testValue, ok := testValueEval.(string) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + return stringSetContains(targetSet, testValue), nil + + case *parser.DataTypeID, *parser.DataTypeInt: + targetSet, ok := targetSetEval.([]int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + testValue, ok := testValueEval.(int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + return intSetContains(targetSet, testValue), nil + } + case *parser.DataTypeStringSet, *parser.DataTypeStringSetQuantum: targetSet, ok := targetSetEval.([]string) if !ok { @@ -76,6 +105,35 @@ func (n *callPlanExpression) EvaluateSetContainsAny(currentRow []interface{}) (i if targetSetEval != nil { switch typ := n.args[0].Type().(type) { + case *parser.DataTypeArray: + switch typ.SubscriptType.(type) { + case *parser.DataTypeString: + targetSet, ok := targetSetEval.([]string) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + testSet, ok := testSetEval.([]string) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + return stringSetContainsAny(targetSet, testSet), nil + + case *parser.DataTypeID, *parser.DataTypeInt: + targetSet, ok := targetSetEval.([]int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + testSet, ok := testSetEval.([]int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + return intSetContainsAny(targetSet, testSet), nil + } + case *parser.DataTypeStringSet: targetSet, ok := targetSetEval.([]string) if !ok { @@ -128,6 +186,35 @@ func (n *callPlanExpression) EvaluateSetContainsAll(currentRow []interface{}) (i if targetSetEval != nil { switch typ := n.args[0].Type().(type) { + case *parser.DataTypeArray: + switch typ.SubscriptType.(type) { + case *parser.DataTypeString: + targetSet, ok := targetSetEval.([]string) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + testSet, ok := testSetEval.([]string) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + return stringSetContainsAll(targetSet, testSet), nil + + case *parser.DataTypeID, *parser.DataTypeInt: + targetSet, ok := targetSetEval.([]int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + testSet, ok := testSetEval.([]int64) + if !ok { + return nil, sql3.NewErrInternalf("unable to convert value") + } + + return intSetContainsAll(targetSet, testSet), nil + } + case *parser.DataTypeStringSet: targetSet, ok := targetSetEval.([]string) if !ok { diff --git a/sql3/test/defs/defs_between.go b/sql3/test/defs/defs_between.go index cb6d582e3..cf604ed30 100644 --- a/sql3/test/defs/defs_between.go +++ b/sql3/test/defs/defs_between.go @@ -90,7 +90,7 @@ var betweenTests = TableTest{ SQLs: sqls( "select ids1 between [100, 102] and [456, 789] from between_all_types", ), - ExpErr: "type 'idset' cannot be used as a range subscript", + ExpErr: "type 'array(int)' cannot be used as a range subscript", }, { SQLs: sqls( @@ -102,7 +102,7 @@ var betweenTests = TableTest{ SQLs: sqls( "select ss1 between ['a', 'b'] and ['c', 'd'] from between_all_types", ), - ExpErr: "type 'stringset' cannot be used as a range subscript", + ExpErr: "type 'array(string)' cannot be used as a range subscript", }, { SQLs: sqls( @@ -209,7 +209,7 @@ var notBetweenTests = TableTest{ SQLs: sqls( "select ids1 not between [100, 102] and [456, 789] from not_between_all_types", ), - ExpErr: "type 'idset' cannot be used as a range subscript", + ExpErr: "type 'array(int)' cannot be used as a range subscript", }, { SQLs: sqls( @@ -221,7 +221,7 @@ var notBetweenTests = TableTest{ SQLs: sqls( "select ss1 not between ['a', 'b'] and ['c', 'd'] from not_between_all_types", ), - ExpErr: "type 'stringset' cannot be used as a range subscript", + ExpErr: "type 'array(string)' cannot be used as a range subscript", }, { SQLs: sqls( diff --git a/sql3/test/defs/defs_inserts.go b/sql3/test/defs/defs_inserts.go index 135e276f3..49b04fe2a 100644 --- a/sql3/test/defs/defs_inserts.go +++ b/sql3/test/defs/defs_inserts.go @@ -115,14 +115,14 @@ var insertTest = TableTest{ SQLs: sqls( "insert into testinsert (_id, a, event) values (4, 40, [101, 150])", ), - ExpErr: "an expression of type 'idset' cannot be assigned to type 'stringset'", + ExpErr: "an expression of type 'array(int)' cannot be assigned to type 'stringset'", }, { // InsertSetsTypeError2 SQLs: sqls( "insert into testinsert (_id, a, ievent) values (4, 40, ['POST', 'GET'])", ), - ExpErr: "an expression of type 'stringset' cannot be assigned to type 'idset'", + ExpErr: "an expression of type 'array(string)' cannot be assigned to type 'idset'", }, { name: "min constraint", diff --git a/sql3/test/defs/defs_set_functions.go b/sql3/test/defs/defs_set_functions.go index fa6c61fe8..f07a73cb4 100644 --- a/sql3/test/defs/defs_set_functions.go +++ b/sql3/test/defs/defs_set_functions.go @@ -296,7 +296,7 @@ var setFunctionTests = TableTest{ SQLs: sqls( "select * from selectwithset where setcontains(event, 1)", ), - ExpErr: "types 'stringset' and 'int' are not equatable", + ExpErr: "an expression of type 'int' cannot be assigned to type 'string'", }, { // SetContainsWrongTypeInt @@ -304,7 +304,7 @@ var setFunctionTests = TableTest{ SQLs: sqls( "select * from selectwithset where setcontains(ievent, 'foo')", ), - ExpErr: "types 'idset' and 'string' are not equatable", + ExpErr: "an expression of type 'string' cannot be assigned to type 'id'", }, { // SetContainsWrongTypeSet @@ -312,7 +312,7 @@ var setFunctionTests = TableTest{ SQLs: sqls( "select * from selectwithset where setcontains(event, ['foo'])", ), - ExpErr: "types 'stringset' and 'stringset' are not equatable", + ExpErr: "an expression of type 'array(string)' cannot be assigned to type 'string'", }, { // SetContainsWrongTypeSet @@ -328,7 +328,14 @@ var setFunctionTests = TableTest{ SQLs: sqls( "select * from selectwithset where setcontains(event, null)", ), - ExpErr: "types 'stringset' and 'void' are not equatable", + ExpHdrs: hdrs( + hdr("_id", fldTypeID), + hdr("a", fldTypeInt), + hdr("b", fldTypeInt), + hdr("event", fldTypeStringSet), + hdr("ievent", fldTypeIDSet), + ), + ExpRows: rows(), }, { // SetContainsWrongTypeSet @@ -376,13 +383,13 @@ var setParameterTests = TableTest{ SQLs: sqls( "select setcontains(['POST', 'GET'], 1)", ), - ExpErr: "types 'stringset' and 'int' are not equatable", + ExpErr: "an expression of type 'int' cannot be assigned to type 'string'", }, { SQLs: sqls( "select setcontains([1, 2], '1')", ), - ExpErr: "types 'idset' and 'string' are not equatable", + ExpErr: "an expression of type 'string' cannot be assigned to type 'int'", }, { @@ -404,14 +411,14 @@ var setParameterTests = TableTest{ "select setcontainsall(['POST', 'GET'], [1, 2])", "select setcontainsany(['POST', 'GET'], [1, 2])", ), - ExpErr: "types 'string' and 'id' are not equatable", + ExpErr: "types 'string' and 'int' are not equatable", }, { SQLs: sqls( "select setcontainsall([1, 2], ['1', '2'])", "select setcontainsany([1, 2], ['1', '2'])", ), - ExpErr: "types 'id' and 'string' are not equatable", + ExpErr: "types 'int' and 'string' are not equatable", }, }, } diff --git a/sql3/test/defs/defs_timequantum.go b/sql3/test/defs/defs_timequantum.go index f1330a170..96257a9cd 100644 --- a/sql3/test/defs/defs_timequantum.go +++ b/sql3/test/defs/defs_timequantum.go @@ -24,13 +24,13 @@ var timeQuantumTest = TableTest{ SQLs: sqls( "insert into time_quantum_insert (_id, i1, ss1, ids1) values (1, 1, {['1']}, {[1]})", ), - ExpErr: "an expression of type 'tuple(stringset)' cannot be assigned to type 'stringsetq'", + ExpErr: "an expression of type 'tuple(array(string))' cannot be assigned to type 'stringsetq'", }, { SQLs: sqls( "insert into time_quantum_insert (_id, i1, ss1, ids1) values (1, 1, ['1'], {[1]})", ), - ExpErr: "an expression of type 'tuple(idset)' cannot be assigned to type 'idsetq'", + ExpErr: "an expression of type 'tuple(array(int))' cannot be assigned to type 'idsetq'", }, { SQLs: sqls( @@ -48,13 +48,13 @@ var timeQuantumTest = TableTest{ SQLs: sqls( "insert into time_quantum_insert (_id, i1, ss1, ids1) values (1, 1, {'2022-01-01T00:00:00Z', [1]}, {[1]})", ), - ExpErr: "an expression of type 'tuple(string, idset)' cannot be assigned to type 'stringsetq'", + ExpErr: "an expression of type 'tuple(string, array(int))' cannot be assigned to type 'stringsetq'", }, { SQLs: sqls( "insert into time_quantum_insert (_id, i1, ss1, ids1) values (1, 1, ['1'], {'2022-01-01T00:00:00Z', ['1']})", ), - ExpErr: "an expression of type 'tuple(string, stringset)' cannot be assigned to type 'idsetq'", + ExpErr: "an expression of type 'tuple(string, array(string))' cannot be assigned to type 'idsetq'", }, { SQLs: sqls(