You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2007/06/11 21:47:50 UTC
svn commit: r546236 - in
/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne:
access/jdbc/ ejbql/ ejbql/parser/
Author: aadamchik
Date: Mon Jun 11 12:47:49 2007
New Revision: 546236
URL: http://svn.apache.org/viewvc?view=rev&rev=546236
Log:
EJBQL joins processing
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLDelegatingVisitor.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLFrom.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java Mon Jun 11 12:47:49 2007
@@ -30,10 +30,10 @@
import org.apache.cayenne.reflect.ClassDescriptor;
public class EJBQLFromTranslator extends EJBQLBaseVisitor {
-
-
+
private EJBQLTranslationContext context;
private String lastTableAlias;
+ private String lastId;
public EJBQLFromTranslator(EJBQLTranslationContext context) {
super(true);
@@ -46,8 +46,10 @@
context.append(',');
}
- lastTableAlias = appendTable(expression.getId());
+ lastId = expression.getId();
+ lastTableAlias = appendTable(lastId);
}
+
return true;
}
@@ -58,7 +60,7 @@
public boolean visitInnerJoin(EJBQLJoin join, int finishedChildIndex) {
if (finishedChildIndex < 0) {
- appendJoin(join, "INNER JOIN");
+ appendJoin(join, "INNER JOIN", true);
}
return true;
}
@@ -70,12 +72,16 @@
public boolean visitOuterJoin(EJBQLJoin join, int finishedChildIndex) {
if (finishedChildIndex < 0) {
- appendJoin(join, "LEFT OUTER JOIN");
+ appendJoin(join, "LEFT OUTER JOIN", false);
}
return true;
}
- private void appendJoin(EJBQLJoin join, String semantics) {
+ void setLastTableAlias(String alias) {
+ this.lastTableAlias = alias;
+ }
+
+ private void appendJoin(EJBQLJoin join, String semantics, boolean reusable) {
String id = join.getId();
@@ -126,7 +132,13 @@
}
context.append(")");
+
+ if (reusable) {
+ context.registerReusableJoin(lastId, incoming.getName(), id);
+ }
+
this.lastTableAlias = targetAlias;
+ this.lastId = id;
}
private String appendTable(String id) {
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java Mon Jun 11 12:47:49 2007
@@ -21,6 +21,9 @@
import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
import org.apache.cayenne.ejbql.EJBQLException;
import org.apache.cayenne.ejbql.EJBQLExpression;
+import org.apache.cayenne.ejbql.parser.EJBQLIdentificationVariable;
+import org.apache.cayenne.ejbql.parser.EJBQLIdentifier;
+import org.apache.cayenne.ejbql.parser.EJBQLInnerJoin;
import org.apache.cayenne.ejbql.parser.EJBQLPath;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.ObjAttribute;
@@ -32,8 +35,11 @@
private EJBQLTranslationContext context;
private ObjEntity currentEntity;
+ private ObjRelationship currentIncoming;
private String lastPathComponent;
private String idPath;
+ private String unresolvedPath;
+ private EJBQLFromTranslator joinAppender;
EJBQLPathTranslator(EJBQLTranslationContext context) {
super(true);
@@ -51,6 +57,7 @@
processLastPath();
}
}
+
return true;
}
@@ -64,18 +71,69 @@
this.currentEntity = descriptor.getEntity();
this.idPath = expression.getText();
+ this.unresolvedPath = idPath;
return true;
}
public boolean visitIdentificationVariable(EJBQLExpression expression) {
- if (this.lastPathComponent != null) {
- this.idPath += '.' + lastPathComponent;
+
+ // TODO: andrus 6/11/2007 - if the path ends with relationship, the last join will
+ // get lost...
+ if (lastPathComponent != null) {
+ resolveJoin();
}
this.lastPathComponent = expression.getText();
return true;
}
+ private void resolveJoin() {
+
+ String newPath = idPath + '.' + lastPathComponent;
+ String oldPath = context.registerReusableJoin(idPath, lastPathComponent, newPath);
+
+ this.unresolvedPath = unresolvedPath + '.' + lastPathComponent;
+
+ if (oldPath != null) {
+ this.idPath = oldPath;
+ }
+ else {
+ // register join
+ EJBQLIdentifier id = new EJBQLIdentifier(-1);
+ id.setText(idPath);
+
+ EJBQLIdentificationVariable idVar = new EJBQLIdentificationVariable(-1);
+ idVar.setText(lastPathComponent);
+
+ EJBQLPath path = new EJBQLPath(-1);
+ path.jjtAddChild(id, 0);
+ path.jjtAddChild(idVar, 1);
+
+ EJBQLIdentifier joinId = new EJBQLIdentifier(-1);
+ joinId.setText(unresolvedPath);
+
+ EJBQLInnerJoin join = new EJBQLInnerJoin(-1);
+ join.jjtAddChild(path, 0);
+ join.jjtAddChild(joinId, 1);
+
+ if (joinAppender == null) {
+ joinAppender = new EJBQLFromTranslator(context);
+ }
+
+ ObjEntity sourceEntity = (ObjEntity) currentIncoming.getSourceEntity();
+
+ context.switchToMarker(EJBQLTranslationContext.FROM_TAIL_MARKER);
+ joinAppender.setLastTableAlias(context.getAlias(idPath, sourceEntity
+ .getDbEntityName()));
+ joinAppender.visitInnerJoin(join, -1);
+ context.switchToMainBuffer();
+
+ this.idPath = newPath;
+ }
+
+
+ }
+
private void processIntermediatePath() {
ObjRelationship relationship = (ObjRelationship) currentEntity
.getRelationship(lastPathComponent);
@@ -87,6 +145,7 @@
+ "'");
}
+ this.currentIncoming = relationship;
this.currentEntity = (ObjEntity) relationship.getTargetEntity();
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java Mon Jun 11 12:47:49 2007
@@ -44,9 +44,15 @@
return true;
}
- public boolean visitFrom(EJBQLExpression expression) {
- context.append(" FROM");
- setDelegate(new EJBQLFromTranslator(context));
+ public boolean visitFrom(EJBQLExpression expression, int finishedChildIndex) {
+ if (finishedChildIndex < 0) {
+ context.append(" FROM");
+ setDelegate(new EJBQLFromTranslator(context));
+ }
+ else if (finishedChildIndex + 1 == expression.getChildrenCount()) {
+ context.markCurrentPosition(EJBQLTranslationContext.FROM_TAIL_MARKER);
+ }
+
return true;
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java Mon Jun 11 12:47:49 2007
@@ -32,19 +32,24 @@
*/
class EJBQLTranslationContext {
+ static final String FROM_TAIL_MARKER = "FROM_TAIL_MARKER";
+
private Map aliases;
private Map bindingVariables;
- private StringBuffer buffer;
+ private StringBuffer mainBuffer;
+ private StringBuffer currentBuffer;
private EJBQLCompiledExpression compiledExpression;
private Map attributes;
+ private Map reusableJoins;
EJBQLTranslationContext(EJBQLCompiledExpression compiledExpression) {
this.compiledExpression = compiledExpression;
- this.buffer = new StringBuffer();
+ this.mainBuffer = new StringBuffer();
+ this.currentBuffer = mainBuffer;
}
SQLTemplate getQuery() {
- String sql = buffer.length() > 0 ? buffer.toString() : null;
+ String sql = mainBuffer.length() > 0 ? mainBuffer.toString() : null;
SQLTemplate query = new SQLTemplate(compiledExpression
.getRootDescriptor()
.getObjectClass(), sql);
@@ -53,6 +58,46 @@
}
/**
+ * Inserts a marker in the SQL, mapped to a StringBuffer that can be later filled with
+ * content.
+ */
+ void markCurrentPosition(String marker) {
+ // make sure we mark the main buffer
+ StringBuffer current = this.currentBuffer;
+
+ try {
+ switchToMainBuffer();
+ String internalMarker = bindParameter(new StringBuffer(), "marker");
+ append("${").append(internalMarker).append("}");
+
+ // register mapping of internal to external marker
+ setAttribute(marker, internalMarker);
+ }
+ finally {
+ this.currentBuffer = current;
+ }
+ }
+
+ void switchToMarker(String marker) {
+ String internalMarker = (String) getAttribute(marker);
+ if (internalMarker == null) {
+ throw new IllegalArgumentException("Invalid marker: " + marker);
+ }
+
+ Object object = bindingVariables.get(internalMarker);
+ if (!(object instanceof StringBuffer)) {
+ throw new IllegalArgumentException("Invalid or missing buffer for marker: "
+ + marker);
+ }
+
+ this.currentBuffer = (StringBuffer) object;
+ }
+
+ void switchToMainBuffer() {
+ this.currentBuffer = this.mainBuffer;
+ }
+
+ /**
* Returns a context "attribute" stored for the given name. Attributes is a state
* preservation mechanism used by translators and have the same scope as the context.
*/
@@ -76,7 +121,7 @@
* Appends a piece of SQL to the internal buffer.
*/
EJBQLTranslationContext append(String chunk) {
- buffer.append(chunk);
+ currentBuffer.append(chunk);
return this;
}
@@ -84,7 +129,7 @@
* Appends a piece of SQL to the internal buffer.
*/
EJBQLTranslationContext append(char chunk) {
- buffer.append(chunk);
+ currentBuffer.append(chunk);
return this;
}
@@ -111,6 +156,28 @@
String var = prefix + bindingVariables.size();
bindingVariables.put(var, value);
return var;
+ }
+
+ /**
+ * Registers a "reusable" join, returning a preexisting ID if the join is already
+ * registered. Reusable normally means an inner join that can be duplicated implicitly
+ * in the path expressions.
+ */
+ String registerReusableJoin(String sourceIdPath, String relationship, String targetId) {
+ if (reusableJoins == null) {
+ reusableJoins = new HashMap();
+ }
+
+ String key = sourceIdPath + ":" + relationship;
+
+ String oldId = (String) reusableJoins.put(key, targetId);
+ if (oldId != null) {
+ // revert back to old id
+ reusableJoins.put(key, oldId);
+ return oldId;
+ }
+
+ return null;
}
/**
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLBaseVisitor.java Mon Jun 11 12:47:49 2007
@@ -157,7 +157,7 @@
return continueFlag;
}
- public boolean visitFrom(EJBQLExpression expression) {
+ public boolean visitFrom(EJBQLExpression expression, int finishedChildIndex) {
return continueFlag;
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLDelegatingVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLDelegatingVisitor.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLDelegatingVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLDelegatingVisitor.java Mon Jun 11 12:47:49 2007
@@ -190,8 +190,10 @@
return delegate != null ? delegate.visitExists(expression) : continueFlag;
}
- public boolean visitFrom(EJBQLExpression expression) {
- return delegate != null ? delegate.visitFrom(expression) : continueFlag;
+ public boolean visitFrom(EJBQLExpression expression, int finishedChildIndex) {
+ return delegate != null
+ ? delegate.visitFrom(expression, finishedChildIndex)
+ : continueFlag;
}
public boolean visitFromItem(EJBQLFromItem expression, int finishedChildIndex) {
@@ -235,9 +237,9 @@
}
public boolean visitInnerFetchJoin(EJBQLJoin join, int finishedChildIndex) {
- return delegate != null ? delegate.visitInnerFetchJoin(
- join,
- finishedChildIndex) : continueFlag;
+ return delegate != null
+ ? delegate.visitInnerFetchJoin(join, finishedChildIndex)
+ : continueFlag;
}
public boolean visitInnerJoin(EJBQLJoin join, int finishedChildIndex) {
@@ -345,9 +347,9 @@
}
public boolean visitOuterFetchJoin(EJBQLJoin join, int finishedChildIndex) {
- return delegate != null ? delegate.visitOuterFetchJoin(
- join,
- finishedChildIndex) : continueFlag;
+ return delegate != null
+ ? delegate.visitOuterFetchJoin(join, finishedChildIndex)
+ : continueFlag;
}
public boolean visitOuterJoin(EJBQLJoin join, int finishedChildIndex) {
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/EJBQLExpressionVisitor.java Mon Jun 11 12:47:49 2007
@@ -140,7 +140,7 @@
boolean visitExists(EJBQLExpression expression);
- boolean visitFrom(EJBQLExpression expression);
+ boolean visitFrom(EJBQLExpression expression, int finishedChildIndex);
boolean visitFromItem(EJBQLFromItem expression, int finishedChildIndex);
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLFrom.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLFrom.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLFrom.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/EJBQLFrom.java Mon Jun 11 12:47:49 2007
@@ -31,6 +31,11 @@
}
protected boolean visitNode(EJBQLExpressionVisitor visitor) {
- return visitor.visitFrom(this);
+ return visitor.visitFrom(this, -1);
+ }
+
+ protected boolean visitChild(EJBQLExpressionVisitor visitor, int childIndex) {
+ return super.visitChild(visitor, childIndex)
+ && visitor.visitFrom(this, childIndex);
}
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java?view=diff&rev=546236&r1=546235&r2=546236
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/ejbql/parser/SimpleNode.java Mon Jun 11 12:47:49 2007
@@ -136,7 +136,7 @@
return (children == null) ? 0 : children.length;
}
- void setText(String text) {
+ public void setText(String text) {
this.text = text;
}