Skip to content

Commit

Permalink
Adding new function decode_base64_utf8 and expr macro
Browse files Browse the repository at this point in the history
  • Loading branch information
pranavbhole committed Sep 9, 2023
1 parent 706b57c commit 491e4b5
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,73 @@ public Object getLiteralValue()
}
}
}

public static class StringDecodeBase64UTFExprMacro implements ExprMacroTable.ExprMacro
{

public static final String NAME = "decode_base64_utf8";

@Override
public Expr apply(List<Expr> args)
{
return new StringDecodeBase64UTFExpression(args);
}

@Override
public String name()
{
return NAME;
}

final class StringDecodeBase64UTFExpression extends ExprMacroTable.BaseScalarMacroFunctionExpr
{
public StringDecodeBase64UTFExpression(List<Expr> args)
{
super(NAME, args);
validationHelperCheckArgumentCount(args, 1);
}

@Override
public ExprEval eval(ObjectBinding bindings)
{
ExprEval<?> toDecode = args.get(0).eval(bindings);
if (toDecode.value() == null) {
return ExprEval.of(null);
}
return new StringExpr(StringUtils.fromUtf8(StringUtils.decodeBase64String(toDecode.asString()))).eval(bindings);
}

@Override
public Expr visit(Shuttle shuttle)
{
return shuttle.visit(apply(shuttle.visitAll(args)));
}

@Nullable
@Override
public ExpressionType getOutputType(InputBindingInspector inspector)
{
return ExpressionType.STRING;
}

@Override
public boolean isLiteral()
{
return args.get(0).isLiteral();
}

@Override
public boolean isNullLiteral()
{
return args.get(0).isNullLiteral();
}

@Nullable
@Override
public Object getLiteralValue()
{
return eval(InputBindings.nilBindings()).value();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
public class ExprMacroTable
{
private static final List<ExprMacro> BUILT_IN = ImmutableList.of(
new BuiltInExprMacros.ComplexDecodeBase64ExprMacro()
new BuiltInExprMacros.ComplexDecodeBase64ExprMacro(),
new BuiltInExprMacros.StringDecodeBase64UTFExprMacro()
);
private static final ExprMacroTable NIL = new ExprMacroTable(Collections.emptyList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,15 @@ public void testRepeat()
assertExpr("repeat(nonexistent, 10)", null);
}

@Test
public void testDecodeBase64UTF()
{
assertExpr("decode_base64_utf8('aGVsbG8=')", "hello");
assertExpr("decode_base64_utf8('V2hlbiBhbiBvbmlvbiBpcyBjdXQsIGNlcnRhaW4gKGxhY2hyeW1hdG9yKSBjb21wb3VuZHMgYXJlIHJlbGVhc2VkIGNhdXNpbmcgdGhlIG5lcnZlcyBhcm91bmQgdGhlIGV5ZXMgKGxhY3JpbWFsIGdsYW5kcykgdG8gYmVjb21lIGlycml0YXRlZC4=')", "When an onion is cut, certain (lachrymator) compounds are released causing the nerves around the eyes (lacrimal glands) to become irritated.");
assertExpr("decode_base64_utf8('eyJ0ZXN0IjogMX0=')", "{\"test\": 1}");
assertExpr("decode_base64_utf8('')", NullHandling.sqlCompatible() ? "" : null);
}

@Test
public void testComplexDecode()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.sql.calcite.expression.builtin;

import org.apache.calcite.sql.SqlFunction;
import org.apache.calcite.sql.SqlFunctionCategory;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.math.expr.BuiltInExprMacros;
import org.apache.druid.sql.calcite.expression.DirectOperatorConversion;
import org.apache.druid.sql.calcite.expression.OperatorConversions;

public class DecodeBase64UTFOperatorConversion extends DirectOperatorConversion
{

private static final SqlFunction SQL_FUNCTION = OperatorConversions
.operatorBuilder(StringUtils.toUpperCase(BuiltInExprMacros.StringDecodeBase64UTFExprMacro.NAME))
.operandTypes(SqlTypeFamily.CHARACTER)
.returnTypeNullable(SqlTypeName.VARCHAR)
.functionCategory(SqlFunctionCategory.STRING)
.build();

public DecodeBase64UTFOperatorConversion()
{
super(SQL_FUNCTION, SQL_FUNCTION.getName());
}

@Override
public SqlOperator calciteOperator()
{
return SQL_FUNCTION;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import org.apache.druid.sql.calcite.expression.builtin.ConcatOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.ContainsOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.DateTruncOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.DecodeBase64UTFOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.ExtractOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.FloorOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.GreatestOperatorConversion;
Expand Down Expand Up @@ -232,6 +233,7 @@ public class DruidOperatorTable implements SqlOperatorTable
.add(new CastOperatorConversion())
.add(new ReinterpretOperatorConversion())
.add(new ComplexDecodeBase64OperatorConversion())
.add(new DecodeBase64UTFOperatorConversion())
.build();

private static final List<SqlOperatorConversion> ARRAY_OPERATOR_CONVERSIONS =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2215,6 +2215,39 @@ public void testFilterOnFloat()
);
}

@Test
public void testDECODE_BASE64_UTF8()
{
testQuery(
"SELECT DECODE_BASE64_UTF8(dim1), DECODE_BASE64_UTF8('aGVsbG8=') FROM druid.foo limit 1",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn(
"v0",
"DECODE_BASE64_UTF8(\"dim1\")",
ColumnType.STRING
),
expressionVirtualColumn(
"v1",
"'hello'",
ColumnType.STRING
)
)
.limit(1)
.columns(ImmutableList.of("v0", "v1"))
.resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"", "hello"}
)
);
}
@Test
public void testFilterOnDouble()
{
Expand Down

0 comments on commit 491e4b5

Please sign in to comment.