>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]>

Reply via email to