Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import org.opensearch.sql.ast.tree.Bin;
import org.opensearch.sql.ast.tree.Chart;
import org.opensearch.sql.ast.tree.CloseCursor;
import org.opensearch.sql.ast.tree.Convert;
import org.opensearch.sql.ast.tree.Dedupe;
import org.opensearch.sql.ast.tree.Eval;
import org.opensearch.sql.ast.tree.Expand;
Expand Down Expand Up @@ -523,6 +524,11 @@ public LogicalPlan visitEval(Eval node, AnalysisContext context) {
return new LogicalEval(child, expressionsBuilder.build());
}

@Override
public LogicalPlan visitConvert(Convert node, AnalysisContext context) {
throw getOnlyForCalciteException("convert");
}

@Override
public LogicalPlan visitAddTotals(AddTotals node, AnalysisContext context) {
throw getOnlyForCalciteException("addtotals");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.opensearch.sql.ast.tree.Bin;
import org.opensearch.sql.ast.tree.Chart;
import org.opensearch.sql.ast.tree.CloseCursor;
import org.opensearch.sql.ast.tree.Convert;
import org.opensearch.sql.ast.tree.Dedupe;
import org.opensearch.sql.ast.tree.Eval;
import org.opensearch.sql.ast.tree.Expand;
Expand Down Expand Up @@ -410,6 +411,10 @@ public T visitFillNull(FillNull fillNull, C context) {
return visitChildren(fillNull, context);
}

public T visitConvert(Convert node, C context) {
return visitChildren(node, context);
}

public T visitPatterns(Patterns patterns, C context) {
return visitChildren(patterns, context);
}
Expand Down
43 changes: 43 additions & 0 deletions core/src/main/java/org/opensearch/sql/ast/tree/Convert.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.ast.tree;

import com.google.common.collect.ImmutableList;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.opensearch.sql.ast.AbstractNodeVisitor;

/** AST node representing the Convert command. */
@Getter
@Setter
@ToString
@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class Convert extends UnresolvedPlan {
private final String timeformat;
private final List<ConvertFunction> convertFunctions;
private UnresolvedPlan child;

@Override
public Convert attach(UnresolvedPlan child) {
this.child = child;
return this;
}

@Override
public List<UnresolvedPlan> getChild() {
return this.child == null ? ImmutableList.of() : ImmutableList.of(this.child);
}

@Override
public <T, C> T accept(AbstractNodeVisitor<T, C> nodeVisitor, C context) {
return nodeVisitor.visitConvert(this, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.ast.tree;

import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

/** Represents a single conversion function within a convert command. */
@Getter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
public class ConvertFunction {
private final String functionName;
private final List<String> fieldList;
private final String asField;
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@
import org.opensearch.sql.ast.tree.Bin;
import org.opensearch.sql.ast.tree.Chart;
import org.opensearch.sql.ast.tree.CloseCursor;
import org.opensearch.sql.ast.tree.Convert;
import org.opensearch.sql.ast.tree.ConvertFunction;
import org.opensearch.sql.ast.tree.Dedupe;
import org.opensearch.sql.ast.tree.Eval;
import org.opensearch.sql.ast.tree.Expand;
Expand Down Expand Up @@ -890,6 +892,65 @@ public RelNode visitEval(Eval node, CalcitePlanContext context) {
return context.relBuilder.peek();
}

@Override
public RelNode visitConvert(Convert node, CalcitePlanContext context) {
visitChildren(node, context);

if (node.getConvertFunctions() == null || node.getConvertFunctions().isEmpty()) {
return context.relBuilder.peek();
}

java.util.Map<String, RexNode> replacements = new java.util.HashMap<>();
List<Pair<String, RexNode>> additions = new ArrayList<>();

for (ConvertFunction convertFunc : node.getConvertFunctions()) {
processConversionFunction(convertFunc, replacements, additions, context);
}

return buildProjectionWithConversions(replacements, additions, context);
}

private void processConversionFunction(
ConvertFunction convertFunc,
java.util.Map<String, RexNode> replacements,
List<Pair<String, RexNode>> additions,
CalcitePlanContext context) {
String functionName = convertFunc.getFunctionName();
List<String> fieldList = convertFunc.getFieldList();
String asField = convertFunc.getAsField();

for (String fieldName : fieldList) {
RexNode field = context.relBuilder.field(fieldName);
RexNode convertCall =
PPLFuncImpTable.INSTANCE.resolve(context.rexBuilder, functionName, field);

if (asField != null) {
additions.add(Pair.of(asField, context.relBuilder.alias(convertCall, asField)));
} else {
replacements.put(fieldName, context.relBuilder.alias(convertCall, fieldName));
}
}
}

private RelNode buildProjectionWithConversions(
java.util.Map<String, RexNode> replacements,
List<Pair<String, RexNode>> additions,
CalcitePlanContext context) {
List<String> originalFields = context.relBuilder.peek().getRowType().getFieldNames();
List<RexNode> projectList = new ArrayList<>();

for (String fieldName : originalFields) {
projectList.add(replacements.getOrDefault(fieldName, context.relBuilder.field(fieldName)));
}

for (Pair<String, RexNode> addition : additions) {
projectList.add(addition.getRight());
}

context.relBuilder.project(projectList);
return context.relBuilder.peek();
}

private void projectPlusOverriding(
List<RexNode> newFields, List<String> newNames, CalcitePlanContext context) {
List<String> originalFieldNames = context.relBuilder.peek().getRowType().getFieldNames();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,18 @@ public enum BuiltinFunctionName {

INTERVAL(FunctionName.of("interval")),

/** PPL Convert Command Functions. */
AUTO(FunctionName.of("auto")),
NUM(FunctionName.of("num")),
CTIME(FunctionName.of("ctime")),
MKTIME(FunctionName.of("mktime")),
DUR2SEC(FunctionName.of("dur2sec")),
MEMK(FunctionName.of("memk")),
MSTIME(FunctionName.of("mstime")),
RMUNIT(FunctionName.of("rmunit")),
RMCOMMA(FunctionName.of("rmcomma")),
NONE(FunctionName.of("none")),

/** Data Type Convert Function. */
CAST_TO_STRING(FunctionName.of("cast_to_string")),
CAST_TO_BYTE(FunctionName.of("cast_to_byte")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,17 @@
import org.opensearch.sql.expression.function.jsonUDF.JsonFunctionImpl;
import org.opensearch.sql.expression.function.jsonUDF.JsonKeysFunctionImpl;
import org.opensearch.sql.expression.function.jsonUDF.JsonSetFunctionImpl;
import org.opensearch.sql.expression.function.udf.AutoConvertFunction;
import org.opensearch.sql.expression.function.udf.CryptographicFunction;
import org.opensearch.sql.expression.function.udf.NoneConvertFunction;
import org.opensearch.sql.expression.function.udf.NumConvertFunction;
import org.opensearch.sql.expression.function.udf.ParseFunction;
import org.opensearch.sql.expression.function.udf.RelevanceQueryFunction;
import org.opensearch.sql.expression.function.udf.RexExtractFunction;
import org.opensearch.sql.expression.function.udf.RexExtractMultiFunction;
import org.opensearch.sql.expression.function.udf.RexOffsetFunction;
import org.opensearch.sql.expression.function.udf.RmcommaConvertFunction;
import org.opensearch.sql.expression.function.udf.RmunitConvertFunction;
import org.opensearch.sql.expression.function.udf.SpanFunction;
import org.opensearch.sql.expression.function.udf.ToNumberFunction;
import org.opensearch.sql.expression.function.udf.ToStringFunction;
Expand Down Expand Up @@ -419,6 +424,14 @@ public class PPLBuiltinOperators extends ReflectiveSqlOperatorTable {
new NumberToStringFunction().toUDF("NUMBER_TO_STRING");
public static final SqlOperator TONUMBER = new ToNumberFunction().toUDF("TONUMBER");
public static final SqlOperator TOSTRING = new ToStringFunction().toUDF("TOSTRING");

// PPL Convert command functions
public static final SqlOperator AUTO = new AutoConvertFunction().toUDF("AUTO");
public static final SqlOperator NUM = new NumConvertFunction().toUDF("NUM");
public static final SqlOperator RMCOMMA = new RmcommaConvertFunction().toUDF("RMCOMMA");
public static final SqlOperator RMUNIT = new RmunitConvertFunction().toUDF("RMUNIT");
public static final SqlOperator NONE = new NoneConvertFunction().toUDF("NONE");

public static final SqlOperator WIDTH_BUCKET =
new org.opensearch.sql.expression.function.udf.binning.WidthBucketFunction()
.toUDF("WIDTH_BUCKET");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.opensearch.sql.expression.function.BuiltinFunctionName.ASIN;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.ATAN;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.ATAN2;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.AUTO;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.AVG;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CBRT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CEIL;
Expand Down Expand Up @@ -157,10 +158,12 @@
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MVJOIN;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MVMAP;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MVZIP;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NONE;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NOT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NOTEQUAL;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NOW;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NULLIF;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NUM;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.OR;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.PERCENTILE_APPROX;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.PERIOD_ADD;
Expand All @@ -184,6 +187,8 @@
import static org.opensearch.sql.expression.function.BuiltinFunctionName.REX_OFFSET;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RIGHT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RINT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RMCOMMA;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RMUNIT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.ROUND;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RTRIM;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.SCALAR_MAX;
Expand Down Expand Up @@ -982,6 +987,14 @@ void populate() {
registerOperator(INTERNAL_PATTERN_PARSER, PPLBuiltinOperators.PATTERN_PARSER);
registerOperator(TONUMBER, PPLBuiltinOperators.TONUMBER);
registerOperator(TOSTRING, PPLBuiltinOperators.TOSTRING);

// Register PPL Convert command functions
registerOperator(AUTO, PPLBuiltinOperators.AUTO);
registerOperator(NUM, PPLBuiltinOperators.NUM);
registerOperator(RMCOMMA, PPLBuiltinOperators.RMCOMMA);
registerOperator(RMUNIT, PPLBuiltinOperators.RMUNIT);
registerOperator(NONE, PPLBuiltinOperators.NONE);

register(
TOSTRING,
(FunctionImp1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.expression.function.udf;

/** PPL auto() conversion function. */
public class AutoConvertFunction extends BaseConversionUDF {

public AutoConvertFunction() {
super("autoConvert");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.expression.function.udf;

import java.util.List;
import org.apache.calcite.adapter.enumerable.NotNullImplementor;
import org.apache.calcite.adapter.enumerable.NullPolicy;
import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.sql.type.ReturnTypes;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
import org.apache.calcite.sql.type.SqlTypeName;
import org.opensearch.sql.calcite.utils.PPLOperandTypes;
import org.opensearch.sql.expression.function.ImplementorUDF;
import org.opensearch.sql.expression.function.UDFOperandMetadata;

/** Base class for PPL conversion functions (auto, num, rmcomma, rmunit). */
public abstract class BaseConversionUDF extends ImplementorUDF {

protected BaseConversionUDF(String conversionMethodName) {
super(new ConversionImplementor(conversionMethodName), NullPolicy.ANY);
}

@Override
public SqlReturnTypeInference getReturnTypeInference() {
return ReturnTypes.explicit(
factory ->
factory.createTypeWithNullability(factory.createSqlType(SqlTypeName.DOUBLE), true));
}

@Override
public UDFOperandMetadata getOperandMetadata() {
return PPLOperandTypes.OPTIONAL_ANY;
}

public static class ConversionImplementor implements NotNullImplementor {
private final String methodName;

public ConversionImplementor(String methodName) {
this.methodName = methodName;
}

@Override
public Expression implement(
RexToLixTranslator translator, RexCall call, List<Expression> translatedOperands) {
Expression fieldValue = translatedOperands.get(0);
Expression result =
Expressions.call(ConversionUtils.class, methodName, Expressions.box(fieldValue));
return Expressions.call(ConversionImplementor.class, "toDoubleOrNull", result);
}

public static Double toDoubleOrNull(Object value) {
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
return null;
}
}
}
Loading
Loading