This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push:
new 4702c3621 CAY-2863 DbEntity qualifiers are no longer applied to JOIN
conditions
4702c3621 is described below
commit 4702c362139f7fe87ef6451a125858e0eaeafa49
Author: Nikita Timofeev <[email protected]>
AuthorDate: Tue Nov 11 16:23:21 2025 +0400
CAY-2863 DbEntity qualifiers are no longer applied to JOIN conditions
---
.../access/translator/select/DbPathProcessor.java | 7 ++++++
.../translator/select/QualifierTranslator.java | 3 ++-
.../access/translator/select/TableTree.java | 25 +++++++++++++++-------
.../access/translator/select/TableTreeStage.java | 14 +++++++++---
.../org/apache/cayenne/exp/path/CayennePath.java | 5 -----
.../org/apache/cayenne/CDOQualifiedEntitiesIT.java | 18 ++++++++++++++++
6 files changed, 55 insertions(+), 17 deletions(-)
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
index 1b16a442b..05498e901 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/DbPathProcessor.java
@@ -61,6 +61,13 @@ class DbPathProcessor extends PathProcessor<DbEntity> {
return;
}
+ // special case when the path should be processed in the context of
the current join clause
+ if(TableTree.CURRENT_ALIAS.equals(next)) {
+ entity = context.getTableTree().nonNullActiveNode().getEntity();
+ appendCurrentPath(next);
+ return;
+ }
+
throw new IllegalStateException("Unable to resolve path: " +
currentDbPath.toString() + "." + next);
}
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
index d6369e118..f01578ec4 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
@@ -296,8 +296,9 @@ class QualifierTranslator implements TraversalHandler {
return new EmptyNode();
} else {
String alias =
context.getTableTree().aliasForPath(result.getLastAttributePath());
+ // special case when the path should be processed in the context
of the current join clause
if(TableTree.CURRENT_ALIAS.equals(alias)) {
- alias = node.getPathAliases().get(TableTree.CURRENT_ALIAS);
+ alias =
context.getTableTree().nonNullActiveNode().getTableAlias();
}
return table(alias).column(result.getLastAttribute()).build();
}
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java
index fe573f6fe..276282c64 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTree.java
@@ -37,6 +37,7 @@ import org.apache.cayenne.map.JoinType;
class TableTree {
public static final String CURRENT_ALIAS = "__current_table_alias__";
+ public static final CayennePath CURRENT_ALIAS_PATH =
CayennePath.of("__current_table_alias__");
/**
* Tables mapped by db path it's spawned by.
@@ -50,6 +51,7 @@ class TableTree {
private final TableTree parentTree;
private final TableTreeNode rootNode;
+ private TableTreeNode activeNode;
private int tableAliasSequence;
TableTree(DbEntity root, TableTree parentTree) {
@@ -64,10 +66,6 @@ class TableTree {
}
void addJoinTable(CayennePath path, DbRelationship relationship, JoinType
joinType, Expression additionalQualifier) {
- // skip adding new node if we are resolving table tree itself
- if(path.marker() == CayennePath.TABLE_TREE_MARKER) {
- return;
- }
TableTreeNode treeNode = tableNodes.get(path);
if (treeNode != null) {
return;
@@ -78,13 +76,13 @@ class TableTree {
}
String aliasForPath(CayennePath attributePath) {
- // should be resolved dynamically by the caller
- if(attributePath.marker() == CayennePath.TABLE_TREE_MARKER) {
- return CURRENT_ALIAS;
- }
if(attributePath.isEmpty()) {
return rootNode.getTableAlias();
}
+ // should be resolved dynamically by the caller
+ if(CURRENT_ALIAS_PATH.equals(attributePath)) {
+ return CURRENT_ALIAS;
+ }
TableTreeNode node = tableNodes.get(attributePath);
if (node == null) {
throw new CayenneRuntimeException("No table for attribute '%s'
found", attributePath);
@@ -100,6 +98,17 @@ class TableTree {
return 't' + String.valueOf(tableAliasSequence++);
}
+ TableTreeNode nonNullActiveNode() {
+ if(activeNode == null) {
+ throw new CayenneRuntimeException("No active TableTree node
found");
+ }
+ return activeNode;
+ }
+
+ void setActiveNode(TableTreeNode activeNode) {
+ this.activeNode = activeNode;
+ }
+
public int getNodeCount() {
return tableNodes.size() + 1;
}
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java
index c1a9e4ca7..d297e32dd 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/translator/select/TableTreeStage.java
@@ -95,7 +95,10 @@ class TableTreeStage implements TranslationStage {
}
dbQualifier = translateToDbPath(node, dbQualifier);
+ // mark table tree node as current to process qualifier
+ context.getTableTree().setActiveNode(node);
Node translatedQualifier =
context.getQualifierTranslator().translate(dbQualifier);
+ context.getTableTree().setActiveNode(null);
return joinBuilder.and(() -> translatedQualifier);
}
@@ -104,9 +107,14 @@ class TableTreeStage implements TranslationStage {
dbQualifier = dbQualifier.transform(input -> {
// here we are not only marking path, but changing ObjPath to DB
if (input instanceof ASTPath) {
- ASTDbPath dbPath = new ASTDbPath(pathToRoot.dot(((ASTPath)
input).getPath()).withMarker(CayennePath.TABLE_TREE_MARKER));
- dbPath.setPathAliases(Map.of(TableTree.CURRENT_ALIAS,
node.getTableAlias()));
- return dbPath;
+ // we do not really care about the parent path, as we do not
need to join any new table here.
+ // so we must tell the path processor that we are processing
exactly this table
+ // TODO: should check qualifiers via related tables if that is
even the thing
+ CayennePath path = ((ASTPath) input).getPath();
+ if(!pathToRoot.isEmpty()) {
+ path = TableTree.CURRENT_ALIAS_PATH.dot(path);
+ }
+ return new ASTDbPath(path);
}
return input;
});
diff --git a/cayenne/src/main/java/org/apache/cayenne/exp/path/CayennePath.java
b/cayenne/src/main/java/org/apache/cayenne/exp/path/CayennePath.java
index 562db0419..3d402d6a2 100644
--- a/cayenne/src/main/java/org/apache/cayenne/exp/path/CayennePath.java
+++ b/cayenne/src/main/java/org/apache/cayenne/exp/path/CayennePath.java
@@ -57,11 +57,6 @@ public interface CayennePath extends
Iterable<CayennePathSegment>, Serializable
*/
int PREFETCH_MARKER = 1;
- /**
- * Marker denotes paths inside tree resolution logic
- */
- int TABLE_TREE_MARKER = 2;
-
/**
* Constant value for an empty path
*/
diff --git
a/cayenne/src/test/java/org/apache/cayenne/CDOQualifiedEntitiesIT.java
b/cayenne/src/test/java/org/apache/cayenne/CDOQualifiedEntitiesIT.java
index 68b722774..7449d0739 100644
--- a/cayenne/src/test/java/org/apache/cayenne/CDOQualifiedEntitiesIT.java
+++ b/cayenne/src/test/java/org/apache/cayenne/CDOQualifiedEntitiesIT.java
@@ -101,9 +101,13 @@ public class CDOQualifiedEntitiesIT extends RuntimeCase {
private void createJoinDataSet() throws Exception {
tQualified3.insert(1, "O1", null);
tQualified3.insert(2, "O2", accessStackAdapter.supportsBoolean() ?
true : 1);
+ tQualified3.insert(3, "11", null);
+ tQualified3.insert(4, "12", accessStackAdapter.supportsBoolean() ?
true : 1);
tQualified4.insert(1, "SHOULD_SELECT", null, 1);
tQualified4.insert(2, "SHOULD_NOT_SELECT", null, 2);
+ tQualified4.insert(3, "SHOULD_SELECT_TOO", null, 3);
+ tQualified4.insert(4, "SHOULD_NOT_SELECT_TOO", null, 4);
}
@Test
@@ -229,6 +233,20 @@ public class CDOQualifiedEntitiesIT extends RuntimeCase {
assertEquals("SHOULD_SELECT", result.get(0).getName());
}
+ @Test
+ public void joinWithQualifierAndAliases() throws Exception {
+ createJoinDataSet();
+
+ List<Qualified4> result = ObjectSelect.query(Qualified4.class)
+
.where(Qualified4.QUALIFIED3.alias("a1").dot(Qualified3.NAME).like("O%"))
+
.or(Qualified4.QUALIFIED3.alias("a2").dot(Qualified3.NAME).like("1%"))
+ .select(context);
+
+ assertEquals(2, result.size());
+ assertEquals("SHOULD_SELECT", result.get(0).getName());
+ assertEquals("SHOULD_SELECT_TOO", result.get(1).getName());
+ }
+
@Test
public void joinWithCustomDbQualifier() throws Exception {
createJoinDataSet();