featurebase/sql3/planner/inbuiltfunctionsset.go
Lory Cloutier fc74c8ecde
Add tests cases for coverage in expressiontypes.go (#2345)
FB-2041
Added tests for typeIsTimeQuantum and typeIsSet and made them pass.
Added tests for DataTypeTuple cases in typesAreAssignmentCompatible.
Timestamp conversion checking is handled before it gets to that
point but I left those branches in as a backstop.
Checking to see if DataType[String,ID]SetQuantum can be assigned
to themselves doesn't appear to be reachable currently but left
those branches in, because something may use them in future.
Added one test to the DAX skip list since it's the IDSetQ version
of a StringSetQ test that was already on there, changed skip list
to refer to both tests by name instead of by number.
2023-03-23 14:17:06 -05:00

208 lines
4.8 KiB
Go

package planner
import (
"strings"
"github.com/featurebasedb/featurebase/v3/sql3"
"github.com/featurebasedb/featurebase/v3/sql3/parser"
)
func (n *callPlanExpression) EvaluateSetContains(currentRow []interface{}) (interface{}, error) {
targetSetEval, err := n.args[0].Evaluate(currentRow)
if err != nil {
return nil, err
}
testValueEval, err := n.args[1].Evaluate(currentRow)
if err != nil {
return nil, err
}
//if either term is null, then null
if testValueEval == nil || targetSetEval == nil {
return nil, nil
}
if targetSetEval != nil {
switch typ := n.args[0].Type().(type) {
case *parser.DataTypeStringSet, *parser.DataTypeStringSetQuantum:
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.DataTypeIDSet, *parser.DataTypeIDSetQuantum:
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
default:
return nil, sql3.NewErrInternalf("unexpected data type '%T'", typ)
}
}
return nil, sql3.NewErrInternalf("unable to to find column '%s' in currentColumns", n.name)
}
func (n *callPlanExpression) EvaluateSetContainsAny(currentRow []interface{}) (interface{}, error) {
targetSetEval, err := n.args[0].Evaluate(currentRow)
if err != nil {
return nil, err
}
testSetEval, err := n.args[1].Evaluate(currentRow)
if err != nil {
return nil, err
}
if targetSetEval != nil {
switch typ := n.args[0].Type().(type) {
case *parser.DataTypeStringSet:
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.DataTypeIDSet:
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
default:
return nil, sql3.NewErrInternalf("unexpected data type '%T'", typ)
}
}
return nil, sql3.NewErrInternalf("unable to to find column '%s' in currentColumns", n.name)
}
func (n *callPlanExpression) EvaluateSetContainsAll(currentRow []interface{}) (interface{}, error) {
targetSetEval, err := n.args[0].Evaluate(currentRow)
if err != nil {
return nil, err
}
testSetEval, err := n.args[1].Evaluate(currentRow)
if err != nil {
return nil, err
}
if targetSetEval != nil {
switch typ := n.args[0].Type().(type) {
case *parser.DataTypeStringSet:
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.DataTypeIDSet:
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
default:
return nil, sql3.NewErrInternalf("unexpected data type '%T'", typ)
}
}
return nil, sql3.NewErrInternalf("unable to to find column '%s' in currentColumns", n.name)
}
func stringSetContains(set []string, val string) bool {
for _, v := range set {
if strings.EqualFold(v, val) {
return true
}
}
return false
}
func stringSetContainsAny(targetSet []string, testSet []string) bool {
for _, test := range testSet {
if stringSetContains(targetSet, test) {
return true
}
}
return false
}
func stringSetContainsAll(targetSet []string, testSet []string) bool {
for _, test := range testSet {
if !stringSetContains(targetSet, test) {
return false
}
}
return true
}
func intSetContains(set []int64, val int64) bool {
for _, v := range set {
if v == val {
return true
}
}
return false
}
func intSetContainsAny(targetSet []int64, testSet []int64) bool {
for _, test := range testSet {
if intSetContains(targetSet, test) {
return true
}
}
return false
}
func intSetContainsAll(targetSet []int64, testSet []int64) bool {
for _, test := range testSet {
if !intSetContains(targetSet, test) {
return false
}
}
return true
}