diff --git a/core/src/main/java/com/orientechnologies/orient/core/sql/executor/FetchFromIndexStep.java b/core/src/main/java/com/orientechnologies/orient/core/sql/executor/FetchFromIndexStep.java index cba382e823b..ebcd0141d7a 100755 --- a/core/src/main/java/com/orientechnologies/orient/core/sql/executor/FetchFromIndexStep.java +++ b/core/src/main/java/com/orientechnologies/orient/core/sql/executor/FetchFromIndexStep.java @@ -434,6 +434,7 @@ private void init( secondValue = ((List) secondValue).get(0); } secondValue = unboxOResult(secondValue); + // TODO unwind collections! Object thirdValue = thirdValueCombinations.get(i).execute((OResult) null, ctx); if (thirdValue instanceof List && ((List) thirdValue).size() == 1 @@ -447,6 +448,44 @@ private void init( secondValue = convertToIndexDefinitionTypes(secondValue, indexDef.getTypes()); thirdValue = convertToIndexDefinitionTypes(thirdValue, indexDef.getTypes()); } catch (Exception e) { + // manage subquery that returns a single collection + if (secondValue instanceof Collection && secondValue.equals(thirdValue)) { + ((Collection) secondValue) + .forEach( + item -> { + Object itemVal = convertToIndexDefinitionTypes(item, indexDef.getTypes()); + if (index.supportsOrderedIterations()) { + + Object from = toBetweenIndexKey(indexDef, itemVal); + Object to = toBetweenIndexKey(indexDef, itemVal); + if (from == null && to == null) { + // manage null value explicitly, as the index API does not seem to work + // correctly in this + // case + stream = getStreamForNullKey(); + storeAcquiredStream(stream); + } else { + stream = + index.streamEntriesBetween( + from, fromKeyIncluded, to, toKeyIncluded, isOrderAsc()); + storeAcquiredStream(stream); + } + + } else if (additionalRangeCondition == null + && allEqualities((OAndBlock) condition)) { + stream = index.streamEntries(toIndexKey(indexDef, itemVal), isOrderAsc()); + storeAcquiredStream(stream); + } else if (isFullTextIndex(index)) { + stream = index.streamEntries(toIndexKey(indexDef, itemVal), isOrderAsc()); + storeAcquiredStream(stream); + } else { + throw new UnsupportedOperationException( + "Cannot evaluate " + this.condition + " on index " + index); + } + nextStreams.add(stream); + }); + } + // some problems in key conversion, so the params do not match the key types continue; } diff --git a/core/src/test/java/com/orientechnologies/orient/core/sql/executor/OSelectStatementExecutionTest.java b/core/src/test/java/com/orientechnologies/orient/core/sql/executor/OSelectStatementExecutionTest.java index baf3ba97400..27f82a74bba 100755 --- a/core/src/test/java/com/orientechnologies/orient/core/sql/executor/OSelectStatementExecutionTest.java +++ b/core/src/test/java/com/orientechnologies/orient/core/sql/executor/OSelectStatementExecutionTest.java @@ -4292,4 +4292,87 @@ public void testComplexIndexChain() { .anyMatch(x -> x instanceof FetchFromIndexStep)); } } + + @Test + public void testIndexWithSubquery() { + String classNamePrefix = "testIndexWithSubquery_"; + db.command("create class " + classNamePrefix + "Ownership extends V abstract;").close(); + db.command("create class " + classNamePrefix + "User extends V;").close(); + db.command("create property " + classNamePrefix + "User.id String;").close(); + db.command( + "create index " + + classNamePrefix + + "User.id ON " + + classNamePrefix + + "User(id) unique;") + .close(); + db.command( + "create class " + classNamePrefix + "Report extends " + classNamePrefix + "Ownership;") + .close(); + db.command("create property " + classNamePrefix + "Report.id String;").close(); + db.command("create property " + classNamePrefix + "Report.label String;").close(); + db.command("create property " + classNamePrefix + "Report.format String;").close(); + db.command("create property " + classNamePrefix + "Report.source String;").close(); + db.command("create class " + classNamePrefix + "hasOwnership extends E;").close(); + db.command("insert into " + classNamePrefix + "User content {id:\"admin\"};"); + db.command( + "insert into " + + classNamePrefix + + "Report content {format:\"PDF\", id:\"rep1\", label:\"Report 1\", source:\"Report1.src\"};") + .close(); + db.command( + "insert into " + + classNamePrefix + + "Report content {format:\"CSV\", id:\"rep2\", label:\"Report 2\", source:\"Report2.src\"};") + .close(); + db.command( + "create edge " + + classNamePrefix + + "hasOwnership from (select from " + + classNamePrefix + + "User) to (select from " + + classNamePrefix + + "Report);") + .close(); + + try (OResultSet rs = + db.query( + "select from " + + classNamePrefix + + "Report where id in (select out('" + + classNamePrefix + + "hasOwnership').id from " + + classNamePrefix + + "User where id = 'admin');")) { + Assert.assertTrue(rs.hasNext()); + rs.next(); + Assert.assertTrue(rs.hasNext()); + rs.next(); + Assert.assertFalse(rs.hasNext()); + } + + db.command( + "create index " + + classNamePrefix + + "Report.id ON " + + classNamePrefix + + "Report(id) unique;") + .close(); + + try (OResultSet rs = + db.query( + "select from " + + classNamePrefix + + "Report where id in (select out('" + + classNamePrefix + + "hasOwnership').id from " + + classNamePrefix + + "User where id = 'admin');")) { + Assert.assertTrue(rs.hasNext()); + rs.next(); + Assert.assertTrue(rs.hasNext()); + rs.next(); + Assert.assertFalse(rs.hasNext()); + } + } }