blob: 4f6099cf3665cda09415cc7535a69909b594b2e2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.math.expr;
import com.google.common.base.Preconditions;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.StringUtils;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Objects;
/**
* Base type for all constant expressions. {@link ConstantExpr} allow for direct value extraction without evaluating
* {@link Expr.ObjectBinding}. {@link ConstantExpr} are terminal nodes of an expression tree, and have no children
* {@link Expr}.
*/
abstract class ConstantExpr implements Expr
{
@Override
public boolean isLiteral()
{
return true;
}
@Override
public void visit(Visitor visitor)
{
visitor.visit(this);
}
@Override
public Expr visit(Shuttle shuttle)
{
return shuttle.visit(this);
}
@Override
public BindingDetails analyzeInputs()
{
return new BindingDetails();
}
@Override
public String stringify()
{
return toString();
}
}
/**
* Base class for typed 'null' value constants (or default value, depending on {@link NullHandling#sqlCompatible})
*/
abstract class NullNumericConstantExpr extends ConstantExpr
{
@Override
public Object getLiteralValue()
{
return null;
}
@Override
public String toString()
{
return NULL_LITERAL;
}
}
class LongExpr extends ConstantExpr
{
private final Long value;
LongExpr(Long value)
{
this.value = Preconditions.checkNotNull(value, "value");
}
@Override
public Object getLiteralValue()
{
return value;
}
@Override
public String toString()
{
return String.valueOf(value);
}
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofLong(value);
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LongExpr longExpr = (LongExpr) o;
return Objects.equals(value, longExpr.value);
}
@Override
public int hashCode()
{
return Objects.hash(value);
}
}
class NullLongExpr extends NullNumericConstantExpr
{
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofLong(null);
}
@Override
public final int hashCode()
{
return NullLongExpr.class.hashCode();
}
@Override
public final boolean equals(Object obj)
{
return obj instanceof NullLongExpr;
}
}
class LongArrayExpr extends ConstantExpr
{
private final Long[] value;
LongArrayExpr(Long[] value)
{
this.value = Preconditions.checkNotNull(value, "value");
}
@Override
public Object getLiteralValue()
{
return value;
}
@Override
public String toString()
{
return Arrays.toString(value);
}
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofLongArray(value);
}
@Override
public String stringify()
{
if (value.length == 0) {
return "<LONG>[]";
}
return StringUtils.format("<LONG>%s", toString());
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LongArrayExpr that = (LongArrayExpr) o;
return Arrays.equals(value, that.value);
}
@Override
public int hashCode()
{
return Arrays.hashCode(value);
}
}
class StringExpr extends ConstantExpr
{
@Nullable
private final String value;
StringExpr(@Nullable String value)
{
this.value = NullHandling.emptyToNullIfNeeded(value);
}
@Nullable
@Override
public Object getLiteralValue()
{
return value;
}
@Override
public String toString()
{
return value;
}
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.of(value);
}
@Override
public String stringify()
{
// escape as javascript string since string literals are wrapped in single quotes
return value == null ? NULL_LITERAL : StringUtils.format("'%s'", StringEscapeUtils.escapeJavaScript(value));
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
StringExpr that = (StringExpr) o;
return Objects.equals(value, that.value);
}
@Override
public int hashCode()
{
return Objects.hash(value);
}
}
class StringArrayExpr extends ConstantExpr
{
private final String[] value;
StringArrayExpr(String[] value)
{
this.value = Preconditions.checkNotNull(value, "value");
}
@Override
public Object getLiteralValue()
{
return value;
}
@Override
public String toString()
{
return Arrays.toString(value);
}
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofStringArray(value);
}
@Override
public String stringify()
{
if (value.length == 0) {
return "<STRING>[]";
}
return StringUtils.format(
"<STRING>[%s]",
ARG_JOINER.join(
Arrays.stream(value)
.map(s -> s == null
? NULL_LITERAL
// escape as javascript string since string literals are wrapped in single quotes
: StringUtils.format("'%s'", StringEscapeUtils.escapeJavaScript(s))
)
.iterator()
)
);
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
StringArrayExpr that = (StringArrayExpr) o;
return Arrays.equals(value, that.value);
}
@Override
public int hashCode()
{
return Arrays.hashCode(value);
}
}
class DoubleExpr extends ConstantExpr
{
private final Double value;
DoubleExpr(Double value)
{
this.value = Preconditions.checkNotNull(value, "value");
}
@Override
public Object getLiteralValue()
{
return value;
}
@Override
public String toString()
{
return String.valueOf(value);
}
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofDouble(value);
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DoubleExpr that = (DoubleExpr) o;
return Objects.equals(value, that.value);
}
@Override
public int hashCode()
{
return Objects.hash(value);
}
}
class NullDoubleExpr extends NullNumericConstantExpr
{
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofDouble(null);
}
@Override
public final int hashCode()
{
return NullDoubleExpr.class.hashCode();
}
@Override
public final boolean equals(Object obj)
{
return obj instanceof NullDoubleExpr;
}
}
class DoubleArrayExpr extends ConstantExpr
{
private final Double[] value;
DoubleArrayExpr(Double[] value)
{
this.value = Preconditions.checkNotNull(value, "value");
}
@Override
public Object getLiteralValue()
{
return value;
}
@Override
public String toString()
{
return Arrays.toString(value);
}
@Override
public ExprEval eval(ObjectBinding bindings)
{
return ExprEval.ofDoubleArray(value);
}
@Override
public String stringify()
{
if (value.length == 0) {
return "<DOUBLE>[]";
}
return StringUtils.format("<DOUBLE>%s", toString());
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DoubleArrayExpr that = (DoubleArrayExpr) o;
return Arrays.equals(value, that.value);
}
@Override
public int hashCode()
{
return Arrays.hashCode(value);
}
}