- All Implemented Interfaces:
NamedWriteable,Writeable,TranslationAware,TranslationAware.SingleValueTranslationAware,Resolvable,EvaluatorMapper
IN operator.
This function has quite "unique" null handling rules around null and multivalued
fields. The null rules are inspired by PostgreSQL, and, presumably, every other
SQL implementation. The multivalue rules are pretty much an extension of the "multivalued
fields are like null in scalars" rule. Here's some examples:
'x' IN ('a', 'b', 'c')=> @{code false}'x' IN ('a', 'x', 'c')=> @{code true}null IN ('a', 'b', 'c')=> @{code null}['x', 'y'] IN ('a', 'b', 'c')=> @{code null} and a warning'x' IN ('a', null, 'c')=> @{code null}'x' IN ('x', null, 'c')=> @{code true}'x' IN ('x', ['a', 'b'], 'c')=> @{code true} and a warning'x' IN ('a', ['a', 'b'], 'c')=> @{code false} and a warning
And here's the decision tree for WHERE x IN (a, b, c):
x IS NULL=> returnnullMV_COUNT(x) > 1=> emit a warning and returnnulla IS NULL AND b IS NULL AND c IS NULL=> returnnullMV_COUNT(a) > 1 OR MV_COUNT(b) > 1 OR MV_COUNT(c) > 1=> emit a warning and continueMV_COUNT(a) > 1 AND MV_COUNT(b) > 1 AND MV_COUNT(c) > 1=> returnnullx == a OR x == b OR x == c=> returntruea IS NULL OR b IS NULL OR c IS NULL=> returnnullelse=>false
I believe the first five entries are *mostly* optimizations and making the Three-valued logic of SQL explicit and integrated with our multivalue field rules. And make all that work with the actual evaluator code. You could probably shorten this to the last three points, but lots of folks aren't familiar with SQL's three-valued logic anyway, so let's be explicit.
Because of this chain of logic we don't use the standard evaluator generators. They'd just
require too many special cases and nothing else quite works like this. I mean, everything
works just like this in that "three-valued logic" sort of way, but not in the "java code"
sort of way. So! Instead of using the standard evaluator generators we use the
String Template generators that we use for things like Block and Vector.
-
Nested Class Summary
Nested classes/interfaces inherited from class org.elasticsearch.xpack.esql.core.expression.Expression
Expression.TypeResolutionNested classes/interfaces inherited from interface org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper
EvaluatorMapper.ToEvaluatorNested classes/interfaces inherited from interface org.elasticsearch.xpack.esql.capabilities.TranslationAware
TranslationAware.FinishedTranslatable, TranslationAware.SingleValueTranslationAware, TranslationAware.TranslatableNested classes/interfaces inherited from interface org.elasticsearch.common.io.stream.Writeable
Writeable.Reader<V>, Writeable.Writer<V> -
Field Summary
FieldsFields inherited from class org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction
MAX_BYTES_REF_RESULT_SIZE -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected booleanareCompatible(DataType left, DataType right) asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) Translates the implementing expression into a Query.protected ExpressiondataType()fold(FoldContext ctx) booleanfoldable()protected NodeInfo<? extends Expression> info()list()replaceChildren(List<Expression> newChildren) protected Expression.TypeResolutionReturns the field that only supports single-value semantics.toEvaluator(EvaluatorMapper.ToEvaluator toEvaluator) Convert this into anEvalOperator.ExpressionEvaluator.translatable(LucenePushdownPredicates pushdownPredicates) Can this instance be translated or not? Usually checks whether the expression arguments are actual fields that exist in Lucene.value()voidwriteTo(StreamOutput out) Methods inherited from class org.elasticsearch.xpack.esql.core.expression.function.Function
arguments, equals, functionName, hashCode, nodeString, nullableMethods inherited from class org.elasticsearch.xpack.esql.core.expression.Expression
canonical, childrenResolved, propertiesToString, references, resolved, semanticEquals, semanticHash, toString, typeResolvedMethods inherited from class org.elasticsearch.xpack.esql.core.tree.Node
anyMatch, children, collect, collectFirstChildren, collectLeaves, doCollectFirst, forEachDown, forEachDown, forEachProperty, forEachPropertyDown, forEachPropertyOnly, forEachPropertyUp, forEachUp, forEachUp, nodeName, nodeProperties, replaceChildrenSameSize, source, sourceLocation, sourceText, transformChildren, transformDown, transformDown, transformDown, transformNodeProps, transformPropertiesDown, transformPropertiesOnly, transformPropertiesUp, transformUp, transformUp, transformUpMethods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, waitMethods inherited from interface org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper
foldMethods inherited from interface org.elasticsearch.xpack.esql.capabilities.TranslationAware
asLuceneQuery
-
Field Details
-
ENTRY
-
-
Constructor Details
-
In
-
-
Method Details
-
value
-
list
-
dataType
- Specified by:
dataTypein classExpression
-
writeTo
- Specified by:
writeToin interfaceWriteable- Throws:
IOException
-
getWriteableName
- Specified by:
getWriteableNamein interfaceNamedWriteable
-
info
- Specified by:
infoin classNode<Expression>
-
replaceChildren
- Specified by:
replaceChildrenin classNode<Expression>
-
foldable
public boolean foldable()- Overrides:
foldablein classExpression
-
fold
- Overrides:
foldin classEsqlScalarFunction
-
areCompatible
-
resolveType
- Overrides:
resolveTypein classExpression
-
canonicalize
- Overrides:
canonicalizein classExpression
-
toEvaluator
public EvalOperator.ExpressionEvaluator.Factory toEvaluator(EvaluatorMapper.ToEvaluator toEvaluator) Description copied from interface:EvaluatorMapperConvert this into anEvalOperator.ExpressionEvaluator.Note for implementors: If you are implementing this function, you should call the passed-in lambda on your children, after doing any other manipulation (casting, etc.) necessary.
Note for Callers: If you are attempting to call this method, and you have an
Expressionand aLayout, you likely want to callEvalMapper.toEvaluator(org.elasticsearch.xpack.esql.core.expression.FoldContext, org.elasticsearch.xpack.esql.core.expression.Expression, org.elasticsearch.xpack.esql.planner.Layout)instead. On the other hand, if you already have something that looks like the parameter for this method, you should call this method with that function.Build an
EvalOperator.ExpressionEvaluator.Factoryfor the tree of expressions rooted at this node. This is only guaranteed to return a sensible evaluator if this node has a valid type. If this node is a subclass ofExpressionthen "valid type" means thatExpression.typeResolved()returns a non-error resolution. If Expression.typeResolved() returns an error then this method may throw. Or return an evaluator that produces garbage. Or return an evaluator that throws when run.- Specified by:
toEvaluatorin interfaceEvaluatorMapper
-
translatable
Description copied from interface:TranslationAwareCan this instance be translated or not? Usually checks whether the expression arguments are actual fields that exist in Lucene. SeeTranslationAware.Translatablefor precisely what can be signaled from this method.- Specified by:
translatablein interfaceTranslationAware
-
asQuery
Description copied from interface:TranslationAwareTranslates the implementing expression into a Query. If during translation a child needs to be translated first, the handler needs to be used even if the child implements this interface as well. This is to ensure that the child is wrapped in a SingleValueQuery if necessary.So use this:
Query childQuery = handler.asQuery(child);and not this:
Query childQuery = child.asQuery(handler);- Specified by:
asQueryin interfaceTranslationAware
-
singleValueField
Description copied from interface:TranslationAware.SingleValueTranslationAwareReturns the field that only supports single-value semantics.- Specified by:
singleValueFieldin interfaceTranslationAware.SingleValueTranslationAware
-