Skip to content

Commit

Permalink
OAK-11214 Support 'IN' restrictions for functions (apache#1813)
Browse files Browse the repository at this point in the history
* OAK-11214 Support 'IN' restrictions for functions

* OAK-11214 Support 'IN' restrictions for functions

* OAK-11214 Support 'IN' restrictions for functions

* OAK-11214 Support 'IN' restrictions for functions
  • Loading branch information
thomasmueller authored Oct 22, 2024
1 parent da0ca2a commit 2031e44
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 6 deletions.
8 changes: 8 additions & 0 deletions oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,10 @@ public Oak with(@NotNull Whiteboard whiteboard) {
LOG.info("Registered improved cost feature: " + QueryEngineSettings.FT_NAME_IMPROVED_IS_NULL_COST);
closer.register(improvedIsNullCostFeature);
queryEngineSettings.setImprovedIsNullCostFeature(improvedIsNullCostFeature);
Feature optimizeInRestrictionsForFunctions = newFeature(QueryEngineSettings.FT_OPTIMIZE_IN_RESTRICTIONS_FOR_FUNCTIONS, whiteboard);
LOG.info("Registered optimize in restrictions for functions feature: " + QueryEngineSettings.FT_OPTIMIZE_IN_RESTRICTIONS_FOR_FUNCTIONS);
closer.register(optimizeInRestrictionsForFunctions);
queryEngineSettings.setOptimizeInRestrictionsForFunctions(optimizeInRestrictionsForFunctions);
}

return this;
Expand Down Expand Up @@ -987,6 +991,10 @@ public void setImprovedIsNullCostFeature(@Nullable Feature feature) {
settings.setImprovedIsNullCostFeature(feature);
}

public void setOptimizeInRestrictionsForFunctions(@Nullable Feature feature) {
settings.setOptimizeInRestrictionsForFunctions(feature);
}

@Override
public void setQueryValidatorPattern(String key, String pattern, String comment, boolean failQuery) {
settings.getQueryValidator().setPattern(key, pattern, comment, failQuery);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public class QueryEngineSettings implements QueryEngineSettingsMBean, QueryLimit

public static final String FT_NAME_IMPROVED_IS_NULL_COST = "FT_OAK-10532";

public static final String FT_OPTIMIZE_IN_RESTRICTIONS_FOR_FUNCTIONS = "FT_OAK-11214";

public static final int DEFAULT_PREFETCH_COUNT = Integer.getInteger(OAK_QUERY_PREFETCH_COUNT, -1);

public static final String OAK_QUERY_FAIL_TRAVERSAL = "oak.queryFailTraversal";
Expand Down Expand Up @@ -114,6 +116,7 @@ public class QueryEngineSettings implements QueryEngineSettingsMBean, QueryLimit

private Feature prefetchFeature;
private Feature improvedIsNullCostFeature;
private Feature optimizeInRestrictionsForFunctions;

private String autoOptionsMappingJson = "{}";
private QueryOptions.AutomaticQueryOptionsMapping autoOptionsMapping = new QueryOptions.AutomaticQueryOptionsMapping(autoOptionsMappingJson);
Expand Down Expand Up @@ -218,6 +221,16 @@ public boolean getImprovedIsNullCost() {
return improvedIsNullCostFeature == null || improvedIsNullCostFeature.isEnabled();
}

public void setOptimizeInRestrictionsForFunctions(@Nullable Feature feature) {
this.optimizeInRestrictionsForFunctions = feature;
}

@Override
public boolean getOptimizeInRestrictionsForFunctions() {
// enabled if the feature toggle is not used
return optimizeInRestrictionsForFunctions == null || optimizeInRestrictionsForFunctions.isEnabled();
}

public String getStrictPathRestriction() {
return strictPathRestriction.name();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ public void restrict(FilterImpl f, Operator operator, PropertyValue v) {
public void restrictList(FilterImpl f, List<PropertyValue> list) {
// "LOWER(x) IN (A, B)" implies x is not null
operand.restrict(f, Operator.NOT_EQUAL, null);
if (!f.getQueryLimits().getOptimizeInRestrictionsForFunctions()) {
return;
}
String fn = getFunction(f.getSelector());
if (fn != null) {
f.restrictPropertyAsList(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, list);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,13 @@ public void restrict(FilterImpl f, Operator operator, PropertyValue v) {

@Override
public void restrictList(FilterImpl f, List<PropertyValue> list) {
// optimizations of type "LOCALNAME(..) IN(A, B)" are not supported
if (!f.getQueryLimits().getOptimizeInRestrictionsForFunctions()) {
return;
}
String fn = getFunction(f.getSelector());
if (fn != null) {
f.restrictPropertyAsList(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, list);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,13 @@ public void restrict(FilterImpl f, Operator operator, PropertyValue v) {

@Override
public void restrictList(FilterImpl f, List<PropertyValue> list) {
// optimizations of type "NAME(..) IN(A, B)" are not supported
if (!f.getQueryLimits().getOptimizeInRestrictionsForFunctions()) {
return;
}
String fn = getFunction(f.getSelector());
if (fn != null) {
f.restrictPropertyAsList(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, list);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.jetbrains.annotations.NotNull;

import org.apache.jackrabbit.guava.common.base.Splitter;
import org.apache.jackrabbit.guava.common.collect.ImmutableSet;

public class NotFullTextSearchImpl extends FullTextSearchImpl {
private static final Set<String> KEYWORDS = Set.of("or");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@ public void restrict(FilterImpl f, Operator operator, PropertyValue v) {

@Override
public void restrictList(FilterImpl f, List<PropertyValue> list) {
// optimizations of type "NAME(..) IN(A, B)" are not supported
if (!f.getQueryLimits().getOptimizeInRestrictionsForFunctions()) {
return;
}
String fn = getFunction(f.getSelector());
if (fn != null) {
f.restrictPropertyAsList(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, list);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ public void restrict(FilterImpl f, Operator operator, PropertyValue v) {
public void restrictList(FilterImpl f, List<PropertyValue> list) {
// "UPPER(x) IN (A, B)" implies x is not null
operand.restrict(f, Operator.NOT_EQUAL, null);
if (!f.getQueryLimits().getOptimizeInRestrictionsForFunctions()) {
return;
}
String fn = getFunction(f.getSelector());
if (fn != null) {
f.restrictPropertyAsList(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, list);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,39 @@ private Filter createFilterSQL(String sql) throws ParseException {
return q.createFilter(true);
}

@Test
public void functionBasedIndexOr() throws Exception {
String sql2 = "select [jcr:path] from [nt:base] where lower([test]) in('hello', 'world')";
assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
"where lower([test]) in('hello', 'world'), " +
"path=*, property=[function*lower*@test=[in(hello, world)], " +
"test=[is not null]])", createFilterSQL(sql2).toString());

sql2 = "select [jcr:path] from [nt:base] where upper([test]) in('hello', 'world')";
assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
"where upper([test]) in('hello', 'world'), " +
"path=*, property=[function*upper*@test=[in(hello, world)], " +
"test=[is not null]])", createFilterSQL(sql2).toString());

sql2 = "select [jcr:path] from [nt:base] where name() in('hello', 'world')";
assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
"where name() in('hello', 'world'), " +
"path=*, property=[function*@:name=[in(hello, world)]])",
createFilterSQL(sql2).toString());

sql2 = "select [jcr:path] from [nt:base] where localname() in('hello', 'world')";
assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
"where localname() in('hello', 'world'), " +
"path=*, property=[function*@:localname=[in(hello, world)]])",
createFilterSQL(sql2).toString());

sql2 = "select [jcr:path] from [nt:base] where path() in('/hello', '/world')";
assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
"where path() in('/hello', '/world'), " +
"path=*, property=[function*@:path=[in(/hello, /world)]])",
createFilterSQL(sql2).toString());
}

@Test
public void functionBasedIndex() throws Exception {
String sql2 = "select [jcr:path] from [nt:base] where lower([test]) = 'hello'";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,22 @@ default boolean getImprovedIsNullCost() {
return true;
}

/**
* See OAK-11214. This method is used for backward compatibility
* (bug compatibility) only.
*
* @return true, except when backward compatibility for OAK-11214 is enabled
*/
default public boolean getOptimizeInRestrictionsForFunctions() {
return true;
}

boolean getFailTraversal();

default String getStrictPathRestriction() {
return StrictPathRestriction.DISABLE.name();
}

/**
* Retrieve the java package names / full qualified class names which should be
* ignored when finding the class starting a query
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
/**
* This package contains oak query index related classes.
*/
@Version("3.0.0")
@Version("3.1.0")
package org.apache.jackrabbit.oak.spi.query;

import org.osgi.annotation.versioning.Version;

0 comments on commit 2031e44

Please sign in to comment.