>From Shahrzad Shirazi <[email protected]>: Shahrzad Shirazi has uploaded this change for review. ( https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20764?usp=email )
Change subject: WIP: Fix index usage for LIKE in UDFs ...................................................................... WIP: Fix index usage for LIKE in UDFs Change-Id: I8387141bc0edf36195934ae4452ad530c63bb4bf --- A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.01.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.02.update.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.03.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.04.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.03.plan A asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.04.plan M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java A asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/LikeExpressionVisitor.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java M hyracks-fullstack/NOTICE 11 files changed, 342 insertions(+), 4 deletions(-) git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/64/20764/1 diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.01.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.01.ddl.sqlpp new file mode 100644 index 0000000..b718bc2 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.01.ddl.sqlpp @@ -0,0 +1,35 @@ +/* + * 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. + */ + +drop dataverse experiments if exists; +create dataverse experiments; +use experiments; + +CREATE TYPE employee AS {id: int}; +CREATE DATASET employees(employee) primary key id; + +create index n on employees(name); + +CREATE FUNCTION is_name_equal(hotel, val) { + hotel.name= val +}; +CREATE FUNCTION is_name_like(hotel, pattern) { + hotel.`name` LIKE pattern +}; + diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.02.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.02.update.sqlpp new file mode 100644 index 0000000..0900514 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.02.update.sqlpp @@ -0,0 +1,22 @@ +/* + * 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. + */ + +use experiments; + +UPSERT INTO ds {"id": 1, "name": "Alec Boehms"}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.03.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.03.query.sqlpp new file mode 100644 index 0000000..80c5027 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.03.query.sqlpp @@ -0,0 +1,23 @@ +/* + * 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. + */ + +USE experiments; + + +explain SELECT h.name FROM ds AS h WHERE is_name_equal(h, "Alec Boehm"); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.04.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.04.query.sqlpp new file mode 100644 index 0000000..4425907 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf-with-like-in/udf-with-like-in.04.query.sqlpp @@ -0,0 +1,23 @@ +/* + * 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. + */ + +USE experiments; + + +explain SELECT h.name FROM ds AS h WHERE is_name_like(h, "Alec Boehm"); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.03.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.03.plan new file mode 100644 index 0000000..34d5618 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.03.plan @@ -0,0 +1,30 @@ +distribute result [$$21] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] +-- DISTRIBUTE_RESULT |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + assign [$$21] <- [{"name": $$22}] project: [$$21] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ASSIGN |PARTITIONED| + project ([$$22]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- STREAM_PROJECT |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + distinct ([$$27]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- PRE_SORTED_DISTINCT_BY |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + order (ASC, $$27) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- STABLE_SORT [$$27(ASC)] |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + select (eq($$22, "Alec Boehm")) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- STREAM_SELECT |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + unnest-map [$$22, $$27] <- index-search("d", 0, "Default", "experiments", "ds", false, false, 1, $$24, 1, $$25, true, true, true) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- BTREE_SEARCH |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + assign [$$24, $$25] <- ["Alec Boehm", "Alec Boehm"] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ASSIGN |PARTITIONED| + empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- EMPTY_TUPLE_SOURCE |PARTITIONED| \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.04.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.04.plan new file mode 100644 index 0000000..34d5618 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cloud/user-defined-functions/udf-with-like-in/udf-with-like-in.04.plan @@ -0,0 +1,30 @@ +distribute result [$$21] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] +-- DISTRIBUTE_RESULT |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + assign [$$21] <- [{"name": $$22}] project: [$$21] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ASSIGN |PARTITIONED| + project ([$$22]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- STREAM_PROJECT |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + distinct ([$$27]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- PRE_SORTED_DISTINCT_BY |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + order (ASC, $$27) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- STABLE_SORT [$$27(ASC)] |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + select (eq($$22, "Alec Boehm")) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- STREAM_SELECT |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + unnest-map [$$22, $$27] <- index-search("d", 0, "Default", "experiments", "ds", false, false, 1, $$24, 1, $$25, true, true, true) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- BTREE_SEARCH |PARTITIONED| + exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + assign [$$24, $$25] <- ["Alec Boehm", "Alec Boehm"] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- ASSIGN |PARTITIONED| + empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0] + -- EMPTY_TUPLE_SOURCE |PARTITIONED| \ No newline at end of file diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java index 32549d9..4b140d4 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java @@ -131,6 +131,9 @@ // Rewrites several variable-arg functions into their corresponding internal list-input functions. rewriteListInputFunctions(); + // Rewrites STRING_LIKE function calls that may have become optimizable after parameter substitution. + rewriteLikeExpression(); + // Rewrites RIGHT OUTER JOINs into LEFT OUTER JOINs if possible rewriteRightJoins(); } diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java index f36d953..b7131b0 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java @@ -59,6 +59,7 @@ import org.apache.asterix.lang.sqlpp.rewrites.visitor.GenerateColumnNameVisitor; import org.apache.asterix.lang.sqlpp.rewrites.visitor.InlineColumnAliasVisitor; import org.apache.asterix.lang.sqlpp.rewrites.visitor.InlineWithExpressionVisitor; +import org.apache.asterix.lang.sqlpp.rewrites.visitor.LikeExpressionVisitor; import org.apache.asterix.lang.sqlpp.rewrites.visitor.OperatorExpressionVisitor; import org.apache.asterix.lang.sqlpp.rewrites.visitor.SelectExcludeRewriteSugarVisitor; import org.apache.asterix.lang.sqlpp.rewrites.visitor.SetOperationVisitor; @@ -211,6 +212,9 @@ // Inlines functions and views loadAndInlineUdfsAndViews(); + // Rewrites STRING_LIKE function calls that may have become optimizable after inlining. + rewriteLikeExpression(); + // Rewrites SQL++ core aggregate function names into internal names rewriteSpecialFunctionNames(); @@ -294,6 +298,12 @@ rewriteTopExpr(operatorExpressionVisitor, null); } + protected void rewriteLikeExpression() throws CompilationException { + // Rewrites STRING_LIKE function calls that may have become optimizable after inlining. + LikeExpressionVisitor likeExpressionVisitor = new LikeExpressionVisitor(context); + rewriteTopExpr(likeExpressionVisitor, null); + } + protected void inlineColumnAlias() throws CompilationException { // Inline column aliases. InlineColumnAliasVisitor inlineColumnAliasVisitor = new InlineColumnAliasVisitor(context); diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/LikeExpressionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/LikeExpressionVisitor.java new file mode 100644 index 0000000..99e7282 --- /dev/null +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/LikeExpressionVisitor.java @@ -0,0 +1,162 @@ +/* + * 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.asterix.lang.sqlpp.rewrites.visitor; + +import static org.apache.asterix.common.utils.ConstantUtil.LIKE_ESCAPE; +import static org.apache.asterix.common.utils.ConstantUtil.PERCENT; +import static org.apache.asterix.common.utils.ConstantUtil.UNDERSCORE; +import static org.apache.asterix.lang.sqlpp.rewrites.visitor.LikeExpressionVisitor.LikePattern.EQUAL; +import static org.apache.asterix.lang.sqlpp.rewrites.visitor.LikeExpressionVisitor.LikePattern.PREFIX; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.functions.FunctionSignature; +import org.apache.asterix.lang.common.base.Expression; +import org.apache.asterix.lang.common.base.ILangExpression; +import org.apache.asterix.lang.common.expression.CallExpr; +import org.apache.asterix.lang.common.expression.LiteralExpr; +import org.apache.asterix.lang.common.expression.OperatorExpr; +import org.apache.asterix.lang.common.literal.StringLiteral; +import org.apache.asterix.lang.common.rewrites.LangRewritingContext; +import org.apache.asterix.lang.common.struct.OperatorType; +import org.apache.asterix.lang.common.util.ExpressionUtils; +import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppExpressionScopingVisitor; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation; +import org.apache.hyracks.api.exceptions.SourceLocation; + +public class LikeExpressionVisitor extends AbstractSqlppExpressionScopingVisitor { + + public LikeExpressionVisitor(LangRewritingContext context) { + super(context); + } + + @Override + public Expression visit(CallExpr callExpr, ILangExpression arg) throws CompilationException { + // Recursively visit arguments first + List<Expression> newExprList = new ArrayList<>(); + for (Expression expr : callExpr.getExprList()) { + newExprList.add(expr.accept(this, callExpr)); + } + callExpr.setExprList(newExprList); + + // Handle STRING_LIKE function calls that may become optimizable after inlining + FunctionSignature funcSignature = callExpr.getFunctionSignature(); + if (funcSignature != null && BuiltinFunctions.STRING_LIKE.equals(funcSignature.createFunctionIdentifier())) { + return processLikeCall(callExpr); + } + + return callExpr; + } + + private Expression processLikeCall(CallExpr callExpr) throws CompilationException { + if (callExpr.getExprList().size() < 2) { + return callExpr; + } + + Expression target = callExpr.getExprList().get(0); + Expression patternExpr = callExpr.getExprList().get(1); + String patternStr = ExpressionUtils.getStringLiteral(patternExpr); + + if (patternStr != null) { + StringBuilder likePatternStr = new StringBuilder(); + LikePattern likePattern = processPattern(patternStr, likePatternStr); + if (likePattern == PREFIX) { + return convertLikeToRange(callExpr, target, likePatternStr.toString()); + } else if (likePattern == EQUAL) { + Expression processedExpr = new LiteralExpr(new StringLiteral(likePatternStr.toString())); + return createOperatorExpression(OperatorType.EQ, target, processedExpr, callExpr.getHints(), + callExpr.getSourceLocation()); + } + } + + // If pattern is not constant or not optimizable, return the call expression as-is + return callExpr; + } + + private Expression createOperatorExpression(OperatorType opType, Expression lhs, Expression rhs, + List<IExpressionAnnotation> hints, SourceLocation sourceLoc) { + OperatorExpr comparison = new OperatorExpr(); + comparison.addOperand(lhs); + comparison.addOperand(rhs); + comparison.addOperator(opType); + comparison.setSourceLocation(sourceLoc); + if (hints != null) { + for (IExpressionAnnotation hint : hints) { + comparison.addHint(hint); + } + } + return comparison; + } + + private Expression convertLikeToRange(CallExpr callExpr, Expression target, String prefix) + throws CompilationException { + int lastCodePoint = prefix.codePointAt(prefix.length() - 1); + String incrementedLastChar = new String(Character.toChars(lastCodePoint + 1)); + String incrementedStr = prefix.substring(0, prefix.length() - 1) + incrementedLastChar; + Expression left = new LiteralExpr(new StringLiteral(prefix)); + Expression right = new LiteralExpr(new StringLiteral(incrementedStr)); + + Expression leftComparison = createOperatorExpression(OperatorType.GE, target, left, callExpr.getHints(), + callExpr.getSourceLocation()); + Expression targetCopy = (Expression) org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil.deepCopy(target); + Expression rightComparison = createOperatorExpression(OperatorType.LT, targetCopy, right, callExpr.getHints(), + callExpr.getSourceLocation()); + + return createOperatorExpression(OperatorType.AND, leftComparison, rightComparison, null, + callExpr.getSourceLocation()); + } + + private static LikePattern processPattern(String pattern, StringBuilder likePatternStr) { + // note: similar logic is applied in StringLikeDescriptor + if (pattern.equals(String.valueOf(PERCENT))) { + return null; + } + LikePattern likePattern = EQUAL; + for (int i = 0, length = pattern.length(); i < length; i++) { + char c = pattern.charAt(i); + if (c == LIKE_ESCAPE) { + char nextChar; + // escape character can't be last, and only %, _ and the escape char are allowed after it + if (i >= length - 1 || ((nextChar = pattern.charAt(i + 1)) != PERCENT && nextChar != UNDERSCORE + && nextChar != LIKE_ESCAPE)) { + return null; + } + likePatternStr.append(nextChar); + ++i; + } else if (c == PERCENT && i == pattern.length() - 1) { + likePattern = PREFIX; + } else if (c == UNDERSCORE || c == PERCENT) { + return null; + } else { + likePatternStr.append(c); + } + } + return likePattern; + } + + enum LikePattern { + PREFIX, + EQUAL + } +} + diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java index 50c4ac9..d045115f 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/OperatorExpressionVisitor.java @@ -90,7 +90,7 @@ return operatorExpr; } - private Expression processLikeOperator(OperatorExpr operatorExpr, OperatorType opType) throws CompilationException { + protected Expression processLikeOperator(OperatorExpr operatorExpr, OperatorType opType) throws CompilationException { switch (opType) { case LIKE: Expression target = operatorExpr.getExprList().get(0); @@ -255,7 +255,7 @@ } private Expression createOperatorExpression(OperatorType opType, Expression lhs, Expression rhs, - List<IExpressionAnnotation> hints, SourceLocation sourceLoc) { + List<IExpressionAnnotation> hints, SourceLocation sourceLoc) { OperatorExpr comparison = new OperatorExpr(); comparison.addOperand(lhs); comparison.addOperand(rhs); @@ -270,7 +270,7 @@ } private Expression createRangeExpression(Expression target, OperatorType leftOp, Expression left, Expression right, - OperatorType rightOp, OperatorExpr operatorExpr) throws CompilationException { + OperatorType rightOp, OperatorExpr operatorExpr) throws CompilationException { Expression leftComparison = createOperatorExpression(leftOp, target, left, operatorExpr.getHints(), operatorExpr.getSourceLocation()); Expression targetCopy = (Expression) SqlppRewriteUtil.deepCopy(target); diff --git a/hyracks-fullstack/NOTICE b/hyracks-fullstack/NOTICE index 722db88..9050c82 100644 --- a/hyracks-fullstack/NOTICE +++ b/hyracks-fullstack/NOTICE @@ -1,5 +1,5 @@ Apache Hyracks and Algebricks -Copyright 2015-2025 The Apache Software Foundation +Copyright 2015-2026 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). -- To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20764?usp=email To unsubscribe, or for help writing mail filters, visit https://asterix-gerrit.ics.uci.edu/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Change-Id: I8387141bc0edf36195934ae4452ad530c63bb4bf Gerrit-Change-Number: 20764 Gerrit-PatchSet: 1 Gerrit-Owner: Shahrzad Shirazi <[email protected]>
