You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(81) |
Nov
|
Dec
|
|---|
|
From: <me...@us...> - 2002-10-01 03:37:33
|
Update of /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne In directory usw-pr-cvs1:/tmp/cvs-serv6637/src/cayenne/java/org/objectstyle/cayenne Modified Files: package.html Log Message: fixed UserGuide link Index: package.html =================================================================== RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/package.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- package.html 8 Sep 2002 22:46:46 -0000 1.1 +++ package.html 1 Oct 2002 03:37:30 -0000 1.2 @@ -3,7 +3,7 @@ Core Cayenne classes and interfaces. This package defines API to work with Cayenne DataObjects. -<p><i>For more information see <a href="../../../../../userguide/index.html" +<p><i>For more information see <a href="../../../../userguide/index.html" target="_top">Cayenne User Guide.</a></i></p> </body> </html> |
|
From: <me...@us...> - 2002-10-01 03:15:29
|
Update of /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne In directory usw-pr-cvs1:/tmp/cvs-serv2251/src/cayenne/java/org/objectstyle/cayenne Modified Files: CayenneDataObject.java Log Message: applied patch 616812 by Craig Miskell Index: CayenneDataObject.java =================================================================== RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/CayenneDataObject.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- CayenneDataObject.java 8 Sep 2002 22:46:46 -0000 1.1 +++ CayenneDataObject.java 1 Oct 2002 03:15:26 -0000 1.2 @@ -52,17 +52,23 @@ * information on the ObjectStyle Group, please see * <http://objectstyle.org/>. * - */ + */ package org.objectstyle.cayenne; -import java.util.*; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; import org.apache.log4j.Logger; import org.objectstyle.cayenne.access.DataContext; import org.objectstyle.cayenne.map.ObjRelationship; import org.objectstyle.cayenne.query.SelectQuery; - /** * A CayenneDataObject is a default implementation of DataObject interface. * It is normally used as a superclass of Cayenne persistent objects. @@ -81,21 +87,21 @@ * Used for debugging. */ public static String persistenceStateString(int persistenceState) { - switch(persistenceState) { - case PersistenceState.TRANSIENT: - return "transient"; - case PersistenceState.NEW: - return "new"; - case PersistenceState.MODIFIED: - return "modified"; - case PersistenceState.COMMITTED: - return "committed"; - case PersistenceState.HOLLOW: - return "hollow"; - case PersistenceState.DELETED: - return "deleted"; - default: - return "unknown"; + switch (persistenceState) { + case PersistenceState.TRANSIENT : + return "transient"; + case PersistenceState.NEW : + return "new"; + case PersistenceState.MODIFIED : + return "modified"; + case PersistenceState.COMMITTED : + return "committed"; + case PersistenceState.HOLLOW : + return "hollow"; + case PersistenceState.DELETED : + return "deleted"; + default : + return "unknown"; } } @@ -104,7 +110,6 @@ protected transient DataContext dataContext; protected HashMap props = new HashMap(); - /** Returns a data context this object is registered with, or null * if this object has no associated DataContext */ public DataContext getDataContext() { @@ -162,34 +167,32 @@ * */ public Object readNestedProperty(String path) { - StringTokenizer toks = new StringTokenizer(path, "."); - - Object obj = null; - CayenneDataObject dataObj = this; - boolean terminal = false; - while(toks.hasMoreTokens()) { - if(terminal) { - throw new CayenneRuntimeException("Invalid path: " + path); - } - String pathComp = toks.nextToken(); - obj = dataObj.readProperty(pathComp); - - if(obj == null) { - return null; - } - else if(obj instanceof CayenneDataObject) { - dataObj = (CayenneDataObject)obj; - } - else { - terminal = true; - } - } - - return obj; - } + StringTokenizer toks = new StringTokenizer(path, "."); + + Object obj = null; + CayenneDataObject dataObj = this; + boolean terminal = false; + while (toks.hasMoreTokens()) { + if (terminal) { + throw new CayenneRuntimeException("Invalid path: " + path); + } + String pathComp = toks.nextToken(); + obj = dataObj.readProperty(pathComp); + + if (obj == null) { + return null; + } else if (obj instanceof CayenneDataObject) { + dataObj = (CayenneDataObject) obj; + } else { + terminal = true; + } + } + + return obj; + } protected Object readProperty(String propName) { - if(persistenceState == PersistenceState.HOLLOW) { + if (persistenceState == PersistenceState.HOLLOW) { dataContext.refetchObject(objectId); } @@ -200,9 +203,8 @@ return props.get(propName); } - protected void writeProperty(String propName, Object val) { - if(persistenceState == PersistenceState.COMMITTED) { + if (persistenceState == PersistenceState.COMMITTED) { persistenceState = PersistenceState.MODIFIED; } @@ -217,82 +219,82 @@ Object toOneTarget = readProperty(relName); // known to be NULL - if(toOneTarget == nullValue) { + if (toOneTarget == nullValue) { return null; } // known to be NOT NULL - if(toOneTarget != null) { - return (DataObject)toOneTarget; + if (toOneTarget != null) { + return (DataObject) toOneTarget; } - // need to fetch - SelectQuery sel = QueryHelper.selectRelationshipObjects(dataContext, objectId, relName); + SelectQuery sel = + QueryHelper.selectRelationshipObjects(dataContext, objectId, relName); List results = dataContext.performQuery(sel); // unexpected - if(results.size() > 1) { - throw new CayenneRuntimeException("error retrieving 'to one' target, found " + results.size()); + if (results.size() > 1) { + throw new CayenneRuntimeException( + "error retrieving 'to one' target, found " + results.size()); } // null target - if(results.size() == 0) { + if (results.size() == 0) { writePropertyDirectly(relName, nullValue); return null; } // found a valid object - DataObject dobj = (DataObject)results.get(0); + DataObject dobj = (DataObject) results.get(0); writePropertyDirectly(relName, dobj); return dobj; } public void removeToManyTarget(String relName, DataObject val, boolean setReverse) { - List relList = (List)readProperty(relName); + List relList = (List) readProperty(relName); relList.remove(val); - if(val != null && setReverse) { + if (val != null && setReverse) { unsetReverseRelationship(relName, val); } } public void addToManyTarget(String relName, DataObject val, boolean setReverse) { - List relList = (List)readProperty(relName); + List relList = (List) readProperty(relName); relList.add(val); - if(val != null && setReverse) + if (val != null && setReverse) setReverseRelationship(relName, val); } public void setToOneDependentTarget(String relName, DataObject val) { - if(val == null) + if (val == null) val = nullValue; setToOneTarget(relName, val, true); } public void setToOneTarget(String relName, DataObject val, boolean setReverse) { - DataObject oldTarget = (DataObject)readPropertyDirectly(relName); - if(oldTarget == val) { + DataObject oldTarget = (DataObject) readPropertyDirectly(relName); + if (oldTarget == val) { return; } - if(setReverse) { + if (setReverse) { // unset old reverse relationship - if(oldTarget != null) + if (oldTarget != null) unsetReverseRelationship(relName, oldTarget); // set new reverse relationship - if(val != null) + if (val != null) setReverseRelationship(relName, val); } writeProperty(relName, val); } - /** * Initializes reverse relationship from object <code>val</code> * to this object. @@ -301,10 +303,13 @@ * to <code>val</code>. */ protected void setReverseRelationship(String relName, DataObject val) { - ObjRelationship rel = (ObjRelationship)dataContext.lookupEntity(objectId.getObjEntityName()).getRelationship(relName); - ObjRelationship revRel = rel.getReverseRelationship(); - if(revRel != null) { - if(revRel.isToMany()) + ObjRelationship rel = + (ObjRelationship) dataContext.lookupEntity( + objectId.getObjEntityName()).getRelationship( + relName); + ObjRelationship revRel = rel.getReverseRelationship(); + if (revRel != null) { + if (revRel.isToMany()) val.addToManyTarget(revRel.getName(), this, false); else val.setToOneTarget(revRel.getName(), this, false); @@ -314,19 +319,21 @@ /** Remove current object from reverse relationship of object <code>val</code> to this object. * @param relName name of relationship from this object to <code>val</code>. */ protected void unsetReverseRelationship(String relName, DataObject val) { - ObjRelationship rel = (ObjRelationship)dataContext.lookupEntity(objectId.getObjEntityName()).getRelationship(relName); + ObjRelationship rel = + (ObjRelationship) dataContext.lookupEntity( + objectId.getObjEntityName()).getRelationship( + relName); ObjRelationship revRel = rel.getReverseRelationship(); - if(revRel != null) { - if(revRel.isToMany()) + if (revRel != null) { + if (revRel.isToMany()) val.removeToManyTarget(revRel.getName(), this, false); - else if(revRel.isToDependentEntity()) + else if (revRel.isToDependentEntity()) val.setToOneTarget(revRel.getName(), nullValue, false); else val.setToOneTarget(revRel.getName(), null, false); } } - public Map getCommittedSnapshot() { return dataContext.getCommittedSnapshot(this); } @@ -335,39 +342,36 @@ return dataContext.takeObjectSnapshot(this); } - - /** A variation of "toString" method, that may be more efficient in some cases. * For example when printing a list of objects into the same String. */ public StringBuffer toStringBuffer(StringBuffer buf, boolean fullDesc) { // log all properties buf.append('{'); - if(fullDesc) + if (fullDesc) appendProperties(buf); - buf.append("<oid: ") - .append(objectId) - .append("; state: ") - .append(persistenceStateString(persistenceState)) - .append(">}\n"); + buf + .append("<oid: ") + .append(objectId) + .append("; state: ") + .append(persistenceStateString(persistenceState)) + .append(">}\n"); return buf; } protected void appendProperties(StringBuffer buf) { buf.append("["); Iterator it = props.keySet().iterator(); - while(it.hasNext()) { + while (it.hasNext()) { Object key = it.next(); buf.append('\t').append(key).append(" => "); Object val = props.get(key); - if(val instanceof CayenneDataObject) { - ((CayenneDataObject)val).toStringBuffer(buf, false); - } else if(val instanceof List) { - buf.append('(') - .append(val.getClass().getName()) - .append(')'); + if (val instanceof CayenneDataObject) { + ((CayenneDataObject) val).toStringBuffer(buf, false); + } else if (val instanceof List) { + buf.append('(').append(val.getClass().getName()).append(')'); } else buf.append(val); @@ -377,16 +381,54 @@ buf.append("]"); } - public String toString() { return toStringBuffer(new StringBuffer(), true).toString(); } - - - /** - * Default implementation does nothing. - * - * @see org.objectstyle.cayenne.DataObject#fetchFinished() - */ - public void fetchFinished() {} + + /** + * Default implementation does nothing. + * + * @see org.objectstyle.cayenne.DataObject#fetchFinished() + */ + public void fetchFinished() {} + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeInt(persistenceState); + + switch (persistenceState) { + //New, modified or transient - write the whole shebang + //The other states (committed, hollow, deleted) all need just ObjectId + case PersistenceState.TRANSIENT : + case PersistenceState.NEW : + case PersistenceState.MODIFIED : + out.writeObject(props); + break; + } + + out.writeObject(objectId); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + this.persistenceState = in.readInt(); + + switch (persistenceState) { + case PersistenceState.TRANSIENT : + case PersistenceState.NEW : + case PersistenceState.MODIFIED : + props = (HashMap) in.readObject(); + break; + case PersistenceState.COMMITTED : + case PersistenceState.HOLLOW : + case PersistenceState.DELETED : + this.persistenceState = PersistenceState.HOLLOW; + //props will be populated when required (readProperty called) + props = new HashMap(); + break; + } + + this.objectId = (ObjectId) in.readObject(); + // dataContext will be set *IFF* the datacontext it came from is also + // deserialized. Setting of datacontext is handled by the datacontext itself + } } |
|
From: <me...@us...> - 2002-10-01 03:15:29
|
Update of /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/access
In directory usw-pr-cvs1:/tmp/cvs-serv2251/src/cayenne/java/org/objectstyle/cayenne/access
Modified Files:
DataContext.java
Log Message:
applied patch 616812 by Craig Miskell
Index: DataContext.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/access/DataContext.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- DataContext.java 19 Sep 2002 03:14:23 -0000 1.10
+++ DataContext.java 1 Oct 2002 03:15:26 -0000 1.11
@@ -110,7 +110,8 @@
//Will not be directly serialized - see read/writeObject for details
protected transient QueryEngine parent;
- protected Map registeredMap = Collections.synchronizedMap(new HashMap());
+ //Must be deserialized slightly differently - see read/writeObject
+ protected transient Map registeredMap = Collections.synchronizedMap(new HashMap());
protected Map committedSnapshots = Collections.synchronizedMap(new HashMap());
protected RelationshipDataSource relDataSource = new RelationshipDataSource();
@@ -1183,6 +1184,10 @@
out.writeObject(this.parent);
//Hope that whatever this.parent is, that it is Serializable
}
+
+ //For writing, just write the objects. They will be serialized possibly
+ // as just objectIds... it's up to the object itself. Reading will do magic
+ out.writeObject(registeredMap);
}
private void readObject(ObjectInputStream in)
@@ -1209,6 +1214,20 @@
+ value);
}
+ //CayenneDataObjects have a transient datacontext
+ // because at deserialize time the datacontext may need to be different
+
+ // than the one at serialize time (for programmer defined reasons).
+ // So, when a dataobject is resurrected because it's datacontext was
+ // serialized, it will then set the objects datacontext to the correctone
+ // If deser'd "otherwise", it will not have a datacontext (good)
+
+ this.registeredMap = (Map) in.readObject();
+ Iterator it = registeredMap.values().iterator();
+ while (it.hasNext()) {
+ DataObject obj = (DataObject) it.next();
+ obj.setDataContext(this);
+ }
}
/**
|
|
From: <me...@us...> - 2002-10-01 02:51:47
|
Update of /cvsroot/cayenne/cayenne/src/tests/java/org/objectstyle/cayenne/access/trans
In directory usw-pr-cvs1:/tmp/cvs-serv26594/src/tests/java/org/objectstyle/cayenne/access/trans
Modified Files:
SelectTranslatorTst.java
Log Message:
added test case checking that translator would not generate unneeded
aliases
Index: SelectTranslatorTst.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/tests/java/org/objectstyle/cayenne/access/trans/SelectTranslatorTst.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** SelectTranslatorTst.java 1 Oct 2002 02:47:15 -0000 1.2
--- SelectTranslatorTst.java 1 Oct 2002 02:51:44 -0000 1.3
***************
*** 269,272 ****
--- 269,316 ----
}
+ /**
+ * Test aliases when the same table used in more then 1 relationship.
+ * Check translation of relationship path "ArtistExhibit.toArtist.artistName"
+ * and "ArtistExhibit.toArtist.paintingArray.paintingTitle".
+ */
+ public void testCreateSqlString6() throws Exception {
+ Connection con = getSharedConnection();
+
+ try {
+ // query with qualifier and ordering
+ q.setObjEntityName("ArtistExhibit");
+ q.setQualifier(
+ ExpressionFactory.binaryPathExp(
+ Expression.LIKE,
+ "toArtist.artistName",
+ "a%"));
+ q.andQualifier(
+ ExpressionFactory.binaryPathExp(
+ Expression.LIKE,
+ "toArtist.paintingArray.paintingTitle",
+ "p%"));
+
+ SelectTranslator transl = buildTranslator(con);
+ String generatedSql = transl.createSqlString();
+ // logObj.warn("Query: " + generatedSql);
+
+ // do some simple assertions to make sure all parts are in
+ assertNotNull(generatedSql);
+ assertTrue(generatedSql.startsWith("SELECT "));
+ assertTrue(generatedSql.indexOf(" FROM ") > 0);
+ assertTrue(generatedSql.indexOf(" WHERE ") > generatedSql.indexOf(" FROM "));
+
+ // check that there is only one distinct alias for the ARTIST table
+ int ind1 = generatedSql.indexOf("ARTIST t", generatedSql.indexOf(" FROM "));
+ assertTrue(ind1 > 0);
+
+ int ind2 = generatedSql.indexOf("ARTIST t", ind1 + 1);
+ assertTrue(ind2 < 0);
+ } finally {
+ con.close();
+ }
+ }
+
+
public void testBuildColumnList1() throws Exception {
Connection con = getSharedConnection();
|
|
From: <me...@us...> - 2002-10-01 02:47:18
|
Update of /cvsroot/cayenne/cayenne/src/tests/java/org/objectstyle/cayenne/access/trans
In directory usw-pr-cvs1:/tmp/cvs-serv24600/src/tests/java/org/objectstyle/cayenne/access/trans
Modified Files:
QualifierTranslatorTst.java SelectTranslatorTst.java
Log Message:
added test case for the recent translator fix
Index: QualifierTranslatorTst.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/tests/java/org/objectstyle/cayenne/access/trans/QualifierTranslatorTst.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** QualifierTranslatorTst.java 8 Sep 2002 23:02:01 -0000 1.1
--- QualifierTranslatorTst.java 1 Oct 2002 02:47:15 -0000 1.2
***************
*** 91,96 ****
}
}
!
! public void testNullQualifier() throws java.lang.Exception {
try {
assertNull(new QualifierTranslator(qa).doTranslation());
--- 91,96 ----
}
}
!
! public void testNullQualifier() throws Exception {
try {
assertNull(new QualifierTranslator(qa).doTranslation());
Index: SelectTranslatorTst.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/tests/java/org/objectstyle/cayenne/access/trans/SelectTranslatorTst.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** SelectTranslatorTst.java 8 Sep 2002 23:02:01 -0000 1.1
--- SelectTranslatorTst.java 1 Oct 2002 02:47:15 -0000 1.2
***************
*** 73,324 ****
public class SelectTranslatorTst extends CayenneTestCase {
! static Logger logObj =
! Logger.getLogger(SelectTranslatorTst.class.getName());
! protected SelectQuery q;
! protected DbEntity artistEnt;
! public SelectTranslatorTst(String name) {
! super(name);
! }
! protected void setUp() throws Exception {
! q = new SelectQuery();
! artistEnt = getSharedDomain().lookupEntity("Artist").getDbEntity();
! }
! private SelectTranslator buildTranslator(Connection con) throws Exception {
! SelectTranslator t = new SelectTranslator();
! t.setAdapter(getSharedNode().getAdapter());
! t.setCon(con);
! t.setEngine(getSharedDomain());
! t.setQuery(q);
! return t;
! }
! /**
! * Tests query creation with qualifier and ordering.
! */
! public void testCreateSqlString1() throws Exception {
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("Artist");
! q.setQualifier(
! ExpressionFactory.binaryExp(
! Expression.LIKE,
! "artistName",
! "a%"));
! q.addOrdering("dateOfBirth", Ordering.ASC);
! String generatedSql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(generatedSql);
! assertTrue(generatedSql.startsWith("SELECT "));
! assertTrue(generatedSql.indexOf(" FROM ") > 0);
! assertTrue(
! generatedSql.indexOf(" WHERE ")
! > generatedSql.indexOf(" FROM "));
! assertTrue(
! generatedSql.indexOf(" ORDER BY ")
! > generatedSql.indexOf(" WHERE "));
! } finally {
! con.close();
! }
! }
! /**
! * Tests query creation with "distinct" specified.
! */
! public void testCreateSqlString2() throws java.lang.Exception {
! Connection con = getSharedConnection();
! try {
! // query with "distinct" set
! q.setObjEntityName("Artist");
! q.setDistinct(true);
! String generatedSql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(generatedSql);
! assertTrue(generatedSql.startsWith("SELECT DISTINCT"));
! } finally {
! con.close();
! }
! }
! /**
! * Tests query creation with relationship from derived entity.
! */
! public void testCreateSqlString3() throws Exception {
! ObjectId id = new ObjectId("Artist", "ARTIST_ID", 35);
! Artist a1 = (Artist) createDataContext().registeredObject(id);
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("ArtistAssets");
! q.setQualifier(ExpressionFactory.matchExp("toArtist", a1));
! String sql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(sql);
! assertTrue(sql.startsWith("SELECT "));
! assertTrue(sql.indexOf(" FROM ") > 0);
! // no WHERE clause
! assertTrue(sql.indexOf(" WHERE ") < 0);
! assertTrue(sql.indexOf(" GROUP BY ") > 0);
! assertTrue(sql.indexOf("ARTIST_ID =") > 0);
! assertTrue(sql.indexOf("ARTIST_ID =") > sql.indexOf(" GROUP BY "));
! } finally {
! con.close();
! }
! }
! /**
! * Tests query creation with relationship from derived entity.
! */
! public void testCreateSqlString4() throws Exception {
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("ArtistAssets");
! q.setParentObjEntityName("Painting");
! q.setParentQualifier(
! ExpressionFactory.matchExp("toArtist.artistName", "abc"));
! q.setQualifier(ExpressionFactory.matchExp("estimatedPrice", new BigDecimal(3)));
! String sql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(sql);
! assertTrue(sql.startsWith("SELECT "));
! assertTrue(sql.indexOf(" FROM ") > 0);
! // no WHERE clause
! assertTrue("WHERE clause is expected: " + sql, sql.indexOf(" WHERE ") > 0);
! assertTrue(
! "GROUP BY clause is expected:" + sql,
! sql.indexOf(" GROUP BY ") > 0);
! assertTrue(
! "HAVING clause is expected",
! sql.indexOf(" HAVING ") > 0);
! assertTrue(sql.indexOf("ARTIST_ID =") > 0);
! assertTrue(
! "Relationship join must be in WHERE: " + sql,
! sql.indexOf("ARTIST_ID =") > sql.indexOf(" WHERE "));
! assertTrue(
! "Relationship join must be in WHERE: " + sql,
! sql.indexOf("ARTIST_ID =") < sql.indexOf(" GROUP BY "));
! assertTrue(
! "Qualifier for related entity must be in WHERE: " + sql,
! sql.indexOf("ARTIST_NAME") > sql.indexOf(" WHERE "));
! assertTrue(
! "Qualifier for related entity must be in WHERE: " + sql,
! sql.indexOf("ARTIST_NAME") < sql.indexOf(" GROUP BY "));
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList1() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with entity that maps one-to-one to DbEntity
! q.setObjEntityName("Artist");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
! List dbAttrs = artistEnt.getAttributeList();
! assertEquals(dbAttrs.size(), columns.size());
! Iterator it = dbAttrs.iterator();
! while (it.hasNext()) {
! assertTrue(columns.contains(it.next()));
! }
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList2() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with custom attributes
! q.setObjEntityName("Artist");
! q.addCustDbAttribute("ARTIST_ID");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
! Object[] dbAttrs =
! new Object[] { artistEnt.getAttribute("ARTIST_ID")};
! assertEquals(dbAttrs.length, columns.size());
! for (int i = 0; i < dbAttrs.length; i++) {
! assertTrue(columns.contains(dbAttrs[i]));
! }
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList3() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with entity that maps to a subset of DbEntity
! q.setObjEntityName("SubPainting");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
! ObjEntity subPainting =
! getSharedDomain().lookupEntity("SubPainting");
! // assert that the number of attributes in the query is right
! // 1 (obj attr) + 1 (pk) = 2
! assertEquals(2, columns.size());
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList4() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with derived entity that maps to a subset of DbEntity
! q.setObjEntityName("ArtistPaintingCounts");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
! ObjEntity countsEnt =
! getSharedDomain().lookupEntity("ArtistPaintingCounts");
! // assert that the number of attributes in the query is right
! // 1 (obj attr) + 1 (pk) = 2
! assertEquals(2, columns.size());
! } finally {
! con.close();
! }
! }
}
--- 73,361 ----
public class SelectTranslatorTst extends CayenneTestCase {
! static Logger logObj = Logger.getLogger(SelectTranslatorTst.class.getName());
! protected SelectQuery q;
! protected DbEntity artistEnt;
! public SelectTranslatorTst(String name) {
! super(name);
! }
! protected void setUp() throws Exception {
! q = new SelectQuery();
! artistEnt = getSharedDomain().lookupEntity("Artist").getDbEntity();
! }
! private SelectTranslator buildTranslator(Connection con) throws Exception {
! SelectTranslator transl =
! (SelectTranslator) getSharedNode().getAdapter().getQueryTranslator(q);
! transl.setEngine(getSharedNode());
! transl.setCon(con);
! return transl;
! }
! /**
! * Tests query creation with qualifier and ordering.
! */
! public void testCreateSqlString1() throws Exception {
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("Artist");
! q.setQualifier(
! ExpressionFactory.binaryExp(Expression.LIKE, "artistName", "a%"));
! q.addOrdering("dateOfBirth", Ordering.ASC);
! String generatedSql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(generatedSql);
! assertTrue(generatedSql.startsWith("SELECT "));
! assertTrue(generatedSql.indexOf(" FROM ") > 0);
! assertTrue(generatedSql.indexOf(" WHERE ") > generatedSql.indexOf(" FROM "));
! assertTrue(
! generatedSql.indexOf(" ORDER BY ") > generatedSql.indexOf(" WHERE "));
! } finally {
! con.close();
! }
! }
! /**
! * Tests query creation with "distinct" specified.
! */
! public void testCreateSqlString2() throws java.lang.Exception {
! Connection con = getSharedConnection();
! try {
! // query with "distinct" set
! q.setObjEntityName("Artist");
! q.setDistinct(true);
! String generatedSql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(generatedSql);
! assertTrue(generatedSql.startsWith("SELECT DISTINCT"));
! } finally {
! con.close();
! }
! }
! /**
! * Tests query creation with relationship from derived entity.
! */
! public void testCreateSqlString3() throws Exception {
! ObjectId id = new ObjectId("Artist", "ARTIST_ID", 35);
! Artist a1 = (Artist) createDataContext().registeredObject(id);
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("ArtistAssets");
! q.setQualifier(ExpressionFactory.matchExp("toArtist", a1));
! String sql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(sql);
! assertTrue(sql.startsWith("SELECT "));
! assertTrue(sql.indexOf(" FROM ") > 0);
! // no WHERE clause
! assertTrue(sql.indexOf(" WHERE ") < 0);
! assertTrue(sql.indexOf(" GROUP BY ") > 0);
! assertTrue(sql.indexOf("ARTIST_ID =") > 0);
! assertTrue(sql.indexOf("ARTIST_ID =") > sql.indexOf(" GROUP BY "));
! } finally {
! con.close();
! }
! }
! /**
! * Tests query creation with relationship from derived entity.
! */
! public void testCreateSqlString4() throws Exception {
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("ArtistAssets");
! q.setParentObjEntityName("Painting");
! q.setParentQualifier(
! ExpressionFactory.matchExp("toArtist.artistName", "abc"));
! q.setQualifier(
! ExpressionFactory.matchExp("estimatedPrice", new BigDecimal(3)));
! String sql = buildTranslator(con).createSqlString();
! // do some simple assertions to make sure all parts are in
! assertNotNull(sql);
! assertTrue(sql.startsWith("SELECT "));
! assertTrue(sql.indexOf(" FROM ") > 0);
! // no WHERE clause
! assertTrue("WHERE clause is expected: " + sql, sql.indexOf(" WHERE ") > 0);
! assertTrue(
! "GROUP BY clause is expected:" + sql,
! sql.indexOf(" GROUP BY ") > 0);
! assertTrue("HAVING clause is expected", sql.indexOf(" HAVING ") > 0);
! assertTrue(sql.indexOf("ARTIST_ID =") > 0);
! assertTrue(
! "Relationship join must be in WHERE: " + sql,
! sql.indexOf("ARTIST_ID =") > sql.indexOf(" WHERE "));
! assertTrue(
! "Relationship join must be in WHERE: " + sql,
! sql.indexOf("ARTIST_ID =") < sql.indexOf(" GROUP BY "));
! assertTrue(
! "Qualifier for related entity must be in WHERE: " + sql,
! sql.indexOf("ARTIST_NAME") > sql.indexOf(" WHERE "));
! assertTrue(
! "Qualifier for related entity must be in WHERE: " + sql,
! sql.indexOf("ARTIST_NAME") < sql.indexOf(" GROUP BY "));
! } finally {
! con.close();
! }
! }
! /**
! * Test aliases when the same table used in more then 1 relationship.
! * Check translation of relationship path "ArtistExhibit.toArtist.artistName"
! * and "ArtistExhibit.toExhibit.toGallery.paintingArray.toArtist.artistName".
! */
! public void testCreateSqlString5() throws Exception {
! Connection con = getSharedConnection();
! try {
! // query with qualifier and ordering
! q.setObjEntityName("ArtistExhibit");
! q.setQualifier(
! ExpressionFactory.binaryPathExp(
! Expression.LIKE,
! "toArtist.artistName",
! "a%"));
! q.andQualifier(
! ExpressionFactory.binaryPathExp(
! Expression.LIKE,
! "toExhibit.toGallery.paintingArray.toArtist.artistName",
! "a%"));
! SelectTranslator transl = buildTranslator(con);
! String generatedSql = transl.createSqlString();
! // logObj.warn("Query: " + generatedSql);
! // do some simple assertions to make sure all parts are in
! assertNotNull(generatedSql);
! assertTrue(generatedSql.startsWith("SELECT "));
! assertTrue(generatedSql.indexOf(" FROM ") > 0);
! assertTrue(generatedSql.indexOf(" WHERE ") > generatedSql.indexOf(" FROM "));
! // check that there are 2 distinct aliases for the ARTIST table
! int ind1 = generatedSql.indexOf("ARTIST t", generatedSql.indexOf(" FROM "));
! assertTrue(ind1 > 0);
! int ind2 = generatedSql.indexOf("ARTIST t", ind1 + 1);
! assertTrue(ind2 > 0);
! assertTrue(
! generatedSql.charAt(ind1 + "ARTIST t".length())
! != generatedSql.charAt(ind2 + "ARTIST t".length()));
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList1() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with entity that maps one-to-one to DbEntity
! q.setObjEntityName("Artist");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
! List dbAttrs = artistEnt.getAttributeList();
! assertEquals(dbAttrs.size(), columns.size());
! Iterator it = dbAttrs.iterator();
! while (it.hasNext()) {
! assertTrue(columns.contains(it.next()));
! }
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList2() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with custom attributes
! q.setObjEntityName("Artist");
! q.addCustDbAttribute("ARTIST_ID");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
! Object[] dbAttrs = new Object[] { artistEnt.getAttribute("ARTIST_ID")};
! assertEquals(dbAttrs.length, columns.size());
! for (int i = 0; i < dbAttrs.length; i++) {
! assertTrue(columns.contains(dbAttrs[i]));
! }
! } finally {
! con.close();
! }
! }
! public void testBuildColumnList3() throws Exception {
! Connection con = getSharedConnection();
! try {
! // configure query with entity that maps to a subset of DbEntity
! q.setObjEntityName("SubPainting");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
! List columns = transl.getColumnList();
!
! ObjEntity subPainting = getSharedDomain().lookupEntity("SubPainting");
!
! // assert that the number of attributes in the query is right
! // 1 (obj attr) + 1 (pk) = 2
! assertEquals(2, columns.size());
!
! } finally {
! con.close();
! }
! }
!
! public void testBuildColumnList4() throws Exception {
! Connection con = getSharedConnection();
!
! try {
! // configure query with derived entity that maps to a subset of DbEntity
! q.setObjEntityName("ArtistPaintingCounts");
! SelectTranslator transl = buildTranslator(con);
! transl.createSqlString();
!
! List columns = transl.getColumnList();
!
! ObjEntity countsEnt = getSharedDomain().lookupEntity("ArtistPaintingCounts");
!
! // assert that the number of attributes in the query is right
! // 1 (obj attr) + 1 (pk) = 2
! assertEquals(2, columns.size());
!
! } finally {
! con.close();
! }
! }
}
|
|
From: <me...@us...> - 2002-10-01 02:07:43
|
Update of /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/access/trans
In directory usw-pr-cvs1:/tmp/cvs-serv8640/src/cayenne/java/org/objectstyle/cayenne/access/trans
Modified Files:
QueryAssembler.java QueryAssemblerHelper.java
SelectTranslator.java
Log Message:
applied patch by Craig Miskell
Index: QueryAssembler.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/access/trans/QueryAssembler.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** QueryAssembler.java 8 Sep 2002 22:46:47 -0000 1.1
--- QueryAssembler.java 1 Oct 2002 02:07:39 -0000 1.2
***************
*** 97,100 ****
--- 97,104 ----
public abstract String createSqlString() throws java.lang.Exception;
+ public String aliasForTable(DbEntity ent, DbRelationship rel) {
+ return aliasForTable(ent); //Default implementation
+ }
+
/**
* Returns a name that can be used as column alias.
***************
*** 128,132 ****
/** Translates internal query into PreparedStatement. */
public PreparedStatement createStatement(Level logLevel) throws Exception {
! long t1 = System.currentTimeMillis();
String sqlStr = createSqlString();
QueryLogger.logQuery(logLevel, sqlStr, values, System.currentTimeMillis() - t1);
--- 132,136 ----
/** Translates internal query into PreparedStatement. */
public PreparedStatement createStatement(Level logLevel) throws Exception {
! long t1 = System.currentTimeMillis();
String sqlStr = createSqlString();
QueryLogger.logQuery(logLevel, sqlStr, values, System.currentTimeMillis() - t1);
***************
*** 155,160 ****
if (attr == null) {
stmt.setObject(i + 1, val);
! }
! else {
int type = attr.getType();
int precision = attr.getPrecision();
--- 159,163 ----
if (attr == null) {
stmt.setObject(i + 1, val);
! } else {
int type = attr.getType();
int precision = attr.getPrecision();
***************
*** 164,169 ****
else {
ExtendedType map =
! adapter.getTypeConverter().getRegisteredType(val.getClass().getName());
! Object jdbcVal = (map == null) ? val : map.toJdbcObject(val, type);
stmt.setObject(i + 1, jdbcVal, type, precision);
}
--- 167,174 ----
else {
ExtendedType map =
! adapter.getTypeConverter().getRegisteredType(
! val.getClass().getName());
! Object jdbcVal =
! (map == null) ? val : map.toJdbcObject(val, type);
stmt.setObject(i + 1, jdbcVal, type, precision);
}
Index: QueryAssemblerHelper.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/access/trans/QueryAssemblerHelper.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** QueryAssemblerHelper.java 8 Sep 2002 22:46:47 -0000 1.1
--- QueryAssemblerHelper.java 1 Oct 2002 02:07:39 -0000 1.2
***************
*** 70,391 ****
*/
public abstract class QueryAssemblerHelper {
! static Logger logObj = Logger.getLogger(QueryAssemblerHelper.class.getName());
! protected QueryAssembler queryAssembler;
! public QueryAssemblerHelper() {}
! /** Creates QueryAssemblerHelper. Sets queryAssembler property. */
! public QueryAssemblerHelper(QueryAssembler queryAssembler) {
! this.queryAssembler = queryAssembler;
! }
! /** Returns parent QueryAssembler that uses this helper. */
! public QueryAssembler getQueryAssembler() {
! return queryAssembler;
! }
! public void setQueryAssembler(QueryAssembler queryAssembler) {
! this.queryAssembler = queryAssembler;
! }
! /** Translates the part of parent translator's query that is supported
! * by this PartTranslator. For example, QualifierTranslator will process
! * qualifier expression, OrderingTranslator - ordering of the query.
! * In the process of translation parent translator is notified of any
! * join tables added (so that it can update its "FROM" clause).
! * Also parent translator is consulted about table aliases to use
! * when translating columns. */
! public abstract String doTranslation();
! public ObjEntity getObjEntity() {
! return getQueryAssembler().getRootEntity();
! }
! public DbEntity getDbEntity() {
! return getQueryAssembler().getRootEntity().getDbEntity();
! }
! /** Processes parts of the OBJ_PATH expression. */
! protected void appendObjPath(StringBuffer buf, Expression pathExp) {
! Iterator it = getObjEntity().resolvePathComponents(pathExp);
! while (it.hasNext()) {
! Object pathComp = it.next();
! if (pathComp instanceof ObjRelationship) {
! ObjRelationship rel = (ObjRelationship) pathComp;
! // if this is a last relationship in the path,
! // it needs special handling
! if (!it.hasNext()) {
! processRelTermination(buf, rel);
! } else {
! // find and add joins ....
! processRelParts(rel);
! }
! } else {
! ObjAttribute objAttr = (ObjAttribute) pathComp;
! processColumn(buf, objAttr.getDbAttribute());
! }
! }
! }
! protected void appendDbPath(StringBuffer buf, Expression pathExp) {
! Iterator it = getDbEntity().resolvePathComponents(pathExp);
! while (it.hasNext()) {
! Object pathComp = it.next();
! if (pathComp instanceof DbRelationship) {
! DbRelationship rel = (DbRelationship) pathComp;
! // if this is a last relationship in the path,
! // it needs special handling
! if (!it.hasNext()) {
! processRelTermination(buf, rel);
! } else {
! // find and add joins ....
! queryAssembler.dbRelationshipAdded(rel);
! }
! } else {
! DbAttribute dbAttr = (DbAttribute) pathComp;
! processColumn(buf, dbAttr);
! }
! }
! }
! /** Appends column name of a column in a root entity. */
! protected void processColumn(StringBuffer buf, Expression nameExp) {
! if (queryAssembler.supportsTableAliases()) {
! String alias = queryAssembler.aliasForTable(getDbEntity());
! buf.append(alias).append('.');
! }
! buf.append(nameExp.getOperand(0));
! }
! protected void processColumn(StringBuffer buf, DbAttribute dbAttr) {
! String alias =
! (queryAssembler.supportsTableAliases())
! ? queryAssembler.aliasForTable((DbEntity) dbAttr.getEntity())
! : null;
! buf.append(dbAttr.getAliasedName(alias));
! }
! /**
! * Appends SQL code to the query buffer to handle <code>val</code> as a
! * parameter to the PreparedStatement being built. Adds <code>val</code>
! * into QueryAssembler parameter list.
! *
! * <p>If <code>val</code> is null, "NULL" is appended to the query. </p>
! *
! * <p>If <code>val</code> is a DataObject, its primary key value is
! * used as a parameter. <i>Only objects with a single column primary key
! * can be used.</i>
! *
! * @param buf query buffer.
! *
! * @param val object that should be appended as a literal to the query.
! * Must be of one of "standard JDBC" types, null or a DataObject.
! *
! * @param attr DbAttribute that has information on what type of parameter
! * is being appended.
! *
! */
! protected void appendLiteral(StringBuffer buf, Object val, DbAttribute attr) {
! if (val == null) {
! buf.append("NULL");
! } else if (val instanceof DataObject) {
! ObjectId id = ((DataObject) val).getObjectId();
! // check if this id is acceptable to be a parameter
! if (id == null) {
! throw new CayenneRuntimeException("Can't use TRANSIENT object as a query parameter.");
! }
! if (id.isTemporary()) {
! throw new CayenneRuntimeException("Can't use NEW object as a query parameter.");
! }
! Map snap = id.getIdSnapshot();
! if (snap.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("Object must have a single primary key column ")
! .append("to serve as a query parameter. ")
! .append("This object has ")
! .append(snap.size())
! .append(": ")
! .append(snap);
! throw new CayenneRuntimeException(msg.toString());
! }
! // checks have been passed, use id value
! appendLiteralDirect(buf, snap.get(snap.keySet().iterator().next()), attr);
! } else {
! appendLiteralDirect(buf, val, attr);
! }
! }
! /**
! * Appends SQL code to the query buffer to handle <code>val</code> as a
! * parameter to the PreparedStatement being built. Adds <code>val</code>
! * into QueryAssembler parameter list.
! *
! *
! * @param buf query buffer
! * @param val object that should be appended as a literal to the query.
! * Must be of one of "standard JDBC" types. Can not be null.
! */
! private final void appendLiteralDirect(
! StringBuffer buf,
! Object val,
! DbAttribute attr) {
! buf.append('?');
! // we are hoping that when processing parameter list,
! // the correct type will be
! // guessed without looking at DbAttribute...
! queryAssembler.addToParamList(attr, val);
! }
! /**
! * Returns database type of expression parameters or
! * null if it can not be determined.
! */
! protected DbAttribute paramsDbType(Expression e) {
! int len = e.getOperandCount();
! // ignore unary expressions
! if (len < 2) {
! return null;
! }
! // naive algorithm:
! // if at least one of the sibling operands is a
! // OBJ_PATH expression, use its attribute type as
! // a final answer.
! for (int i = 0; i < len; i++) {
! Object op = e.getOperand(i);
! if (op instanceof Expression) {
! Expression ope = (Expression) op;
! if (ope.getType() == Expression.OBJ_PATH) {
! Iterator it = getObjEntity().resolvePathComponents(ope);
! while (it.hasNext()) {
! Object pathComp = it.next();
! if (pathComp instanceof ObjAttribute) {
! return ((ObjAttribute) pathComp).getDbAttribute();
! }
! }
! }
! }
! }
! return null;
! }
! /**
! * Processes ObjRelationship. Decomposes it into DbRelationships
! * and appends parts to the query buffer.
! */
! protected void processRelParts(ObjRelationship rel) {
! Iterator it = rel.getDbRelationshipList().iterator();
! while (it.hasNext()) {
! queryAssembler.dbRelationshipAdded((DbRelationship) it.next());
! }
! }
! /** Processes case when an OBJ_PATH expression ends with relationship.
! * If this is a "to many" relationship, a join is added and a column
! * expression for the target entity primary key. If this is a "to one"
! * relationship, column expresion for the source foreign key is added.
! */
! protected void processRelTermination(StringBuffer buf, ObjRelationship rel) {
! if (rel.isToMany()) {
! // append joins
! processRelParts(rel);
! }
! List dbRels = rel.getDbRelationshipList();
! // get last DbRelationship on the list
! DbRelationship dbRel = (DbRelationship) dbRels.get(dbRels.size() - 1);
! List joins = dbRel.getJoins();
! if (joins.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("OBJ_PATH expressions are only supported ")
! .append("for a single-join relationships. ")
! .append("This relationship has ")
! .append(joins.size())
! .append(" joins.");
! throw new CayenneRuntimeException(msg.toString());
! }
! DbAttributePair join = (DbAttributePair) joins.get(0);
- DbAttribute att = join.getSource();
- processColumn(buf, att);
- }
-
/**
* Handles case when a DB_NAME expression ends with relationship.
! * If this is a "to many" relationship, a join is added and a column
! * expression for the target entity primary key. If this is a "to one"
! * relationship, column expresion for the source foreign key is added.
! */
! protected void processRelTermination(StringBuffer buf, DbRelationship rel) {
! if (rel.isToMany()) {
! // append joins
! queryAssembler.dbRelationshipAdded(rel);
! }
!
! // get last DbRelationship on the list
! List joins = rel.getJoins();
! if (joins.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("OBJ_PATH expressions are only supported ")
! .append("for a single-join relationships. ")
! .append("This relationship has ")
! .append(joins.size())
! .append(" joins.");
! throw new CayenneRuntimeException(msg.toString());
! }
! DbAttributePair join = (DbAttributePair) joins.get(0);
! DbAttribute att = null;
! if (rel.isToMany()) {
! DbEntity ent = (DbEntity) join.getTarget().getEntity();
! List pk = ent.getPrimaryKey();
! if (pk.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("DB_NAME expressions can only support ")
! .append("targets with a single column PK. ")
! .append("This entity has ")
! .append(pk.size())
! .append(" columns in primary key.");
! throw new CayenneRuntimeException(msg.toString());
! }
! att = (DbAttribute) pk.get(0);
! } else {
! att = join.getSource();
! }
! processColumn(buf, att);
! }
}
--- 70,410 ----
*/
public abstract class QueryAssemblerHelper {
! static Logger logObj = Logger.getLogger(QueryAssemblerHelper.class.getName());
! protected QueryAssembler queryAssembler;
! public QueryAssemblerHelper() {}
! /** Creates QueryAssemblerHelper. Sets queryAssembler property. */
! public QueryAssemblerHelper(QueryAssembler queryAssembler) {
! this.queryAssembler = queryAssembler;
! }
! /** Returns parent QueryAssembler that uses this helper. */
! public QueryAssembler getQueryAssembler() {
! return queryAssembler;
! }
! public void setQueryAssembler(QueryAssembler queryAssembler) {
! this.queryAssembler = queryAssembler;
! }
! /** Translates the part of parent translator's query that is supported
! * by this PartTranslator. For example, QualifierTranslator will process
! * qualifier expression, OrderingTranslator - ordering of the query.
! * In the process of translation parent translator is notified of any
! * join tables added (so that it can update its "FROM" clause).
! * Also parent translator is consulted about table aliases to use
! * when translating columns. */
! public abstract String doTranslation();
! public ObjEntity getObjEntity() {
! return getQueryAssembler().getRootEntity();
! }
! public DbEntity getDbEntity() {
! return getQueryAssembler().getRootEntity().getDbEntity();
! }
! /** Processes parts of the OBJ_PATH expression. */
! protected void appendObjPath(StringBuffer buf, Expression pathExp) {
! Iterator it = getObjEntity().resolvePathComponents(pathExp);
! ObjRelationship lastRelationship = null;
! while (it.hasNext()) {
! Object pathComp = it.next();
! if (pathComp instanceof ObjRelationship) {
! ObjRelationship rel = (ObjRelationship) pathComp;
! // if this is a last relationship in the path,
! // it needs special handling
! if (!it.hasNext()) {
! processRelTermination(buf, rel);
! } else {
! // find and add joins ....
! processRelParts(rel);
! }
! lastRelationship = rel;
! } else {
! ObjAttribute objAttr = (ObjAttribute) pathComp;
! if (lastRelationship != null) {
! DbRelationship lastDbRel =
! (DbRelationship) lastRelationship.getDbRelationshipList().get(0);
! processColumn(buf, objAttr.getDbAttribute(), lastDbRel);
! } else {
! processColumn(buf, objAttr.getDbAttribute());
! }
! }
! }
! }
! protected void appendDbPath(StringBuffer buf, Expression pathExp) {
! Iterator it = getDbEntity().resolvePathComponents(pathExp);
! while (it.hasNext()) {
! Object pathComp = it.next();
! if (pathComp instanceof DbRelationship) {
! DbRelationship rel = (DbRelationship) pathComp;
! // if this is a last relationship in the path,
! // it needs special handling
! if (!it.hasNext()) {
! processRelTermination(buf, rel);
! } else {
! // find and add joins ....
! queryAssembler.dbRelationshipAdded(rel);
! }
! } else {
! DbAttribute dbAttr = (DbAttribute) pathComp;
! processColumn(buf, dbAttr);
! }
! }
! }
! /** Appends column name of a column in a root entity. */
! protected void processColumn(StringBuffer buf, Expression nameExp) {
! if (queryAssembler.supportsTableAliases()) {
! String alias = queryAssembler.aliasForTable(getDbEntity());
! buf.append(alias).append('.');
! }
! buf.append(nameExp.getOperand(0));
! }
! protected void processColumn(
! StringBuffer buf,
! DbAttribute dbAttr,
! DbRelationship rel) {
! String alias =
! (queryAssembler.supportsTableAliases())
! ? queryAssembler.aliasForTable((DbEntity) dbAttr.getEntity(), rel)
! : null;
! buf.append(dbAttr.getAliasedName(alias));
! }
! protected void processColumn(StringBuffer buf, DbAttribute dbAttr) {
! String alias =
! (queryAssembler.supportsTableAliases())
! ? queryAssembler.aliasForTable((DbEntity) dbAttr.getEntity())
! : null;
! buf.append(dbAttr.getAliasedName(alias));
! }
! /**
! * Appends SQL code to the query buffer to handle <code>val</code> as a
! * parameter to the PreparedStatement being built. Adds <code>val</code>
! * into QueryAssembler parameter list.
! *
! * <p>If <code>val</code> is null, "NULL" is appended to the query. </p>
! *
! * <p>If <code>val</code> is a DataObject, its primary key value is
! * used as a parameter. <i>Only objects with a single column primary key
! * can be used.</i>
! *
! * @param buf query buffer.
! *
! * @param val object that should be appended as a literal to the query.
! * Must be of one of "standard JDBC" types, null or a DataObject.
! *
! * @param attr DbAttribute that has information on what type of parameter
! * is being appended.
! *
! */
! protected void appendLiteral(StringBuffer buf, Object val, DbAttribute attr) {
! if (val == null) {
! buf.append("NULL");
! } else if (val instanceof DataObject) {
! ObjectId id = ((DataObject) val).getObjectId();
! // check if this id is acceptable to be a parameter
! if (id == null) {
! throw new CayenneRuntimeException("Can't use TRANSIENT object as a query parameter.");
! }
! if (id.isTemporary()) {
! throw new CayenneRuntimeException("Can't use NEW object as a query parameter.");
! }
! Map snap = id.getIdSnapshot();
! if (snap.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("Object must have a single primary key column ")
! .append("to serve as a query parameter. ")
! .append("This object has ")
! .append(snap.size())
! .append(": ")
! .append(snap);
! throw new CayenneRuntimeException(msg.toString());
! }
! // checks have been passed, use id value
! appendLiteralDirect(buf, snap.get(snap.keySet().iterator().next()), attr);
! } else {
! appendLiteralDirect(buf, val, attr);
! }
! }
! /**
! * Appends SQL code to the query buffer to handle <code>val</code> as a
! * parameter to the PreparedStatement being built. Adds <code>val</code>
! * into QueryAssembler parameter list.
! *
! *
! * @param buf query buffer
! * @param val object that should be appended as a literal to the query.
! * Must be of one of "standard JDBC" types. Can not be null.
! */
! private final void appendLiteralDirect(
! StringBuffer buf,
! Object val,
! DbAttribute attr) {
! buf.append('?');
! // we are hoping that when processing parameter list,
! // the correct type will be
! // guessed without looking at DbAttribute...
! queryAssembler.addToParamList(attr, val);
! }
! /**
! * Returns database type of expression parameters or
! * null if it can not be determined.
! */
! protected DbAttribute paramsDbType(Expression e) {
! int len = e.getOperandCount();
! // ignore unary expressions
! if (len < 2) {
! return null;
! }
! // naive algorithm:
! // if at least one of the sibling operands is a
! // OBJ_PATH expression, use its attribute type as
! // a final answer.
! for (int i = 0; i < len; i++) {
! Object op = e.getOperand(i);
! if (op instanceof Expression) {
! Expression ope = (Expression) op;
! if (ope.getType() == Expression.OBJ_PATH) {
! Iterator it = getObjEntity().resolvePathComponents(ope);
! while (it.hasNext()) {
! Object pathComp = it.next();
! if (pathComp instanceof ObjAttribute) {
! return ((ObjAttribute) pathComp).getDbAttribute();
! }
! }
! }
! }
! }
! return null;
! }
! /**
! * Processes ObjRelationship. Decomposes it into DbRelationships
! * and appends parts to the query buffer.
! */
! protected void processRelParts(ObjRelationship rel) {
! Iterator it = rel.getDbRelationshipList().iterator();
! while (it.hasNext()) {
! queryAssembler.dbRelationshipAdded((DbRelationship) it.next());
! }
! }
! /** Processes case when an OBJ_PATH expression ends with relationship.
! * If this is a "to many" relationship, a join is added and a column
! * expression for the target entity primary key. If this is a "to one"
! * relationship, column expresion for the source foreign key is added.
! */
! protected void processRelTermination(StringBuffer buf, ObjRelationship rel) {
! if (rel.isToMany()) {
! // append joins
! processRelParts(rel);
! }
! List dbRels = rel.getDbRelationshipList();
! // get last DbRelationship on the list
! DbRelationship dbRel = (DbRelationship) dbRels.get(dbRels.size() - 1);
! List joins = dbRel.getJoins();
! if (joins.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("OBJ_PATH expressions are only supported ")
! .append("for a single-join relationships. ")
! .append("This relationship has ")
! .append(joins.size())
! .append(" joins.");
!
! throw new CayenneRuntimeException(msg.toString());
! }
!
! DbAttributePair join = (DbAttributePair) joins.get(0);
!
! DbAttribute att = join.getSource();
! processColumn(buf, att);
! }
/**
* Handles case when a DB_NAME expression ends with relationship.
! * If this is a "to many" relationship, a join is added and a column
! * expression for the target entity primary key. If this is a "to one"
! * relationship, column expresion for the source foreign key is added.
! */
! protected void processRelTermination(StringBuffer buf, DbRelationship rel) {
! if (rel.isToMany()) {
! // append joins
! queryAssembler.dbRelationshipAdded(rel);
! }
! // get last DbRelationship on the list
! List joins = rel.getJoins();
! if (joins.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("OBJ_PATH expressions are only supported ")
! .append("for a single-join relationships. ")
! .append("This relationship has ")
! .append(joins.size())
! .append(" joins.");
! throw new CayenneRuntimeException(msg.toString());
! }
! DbAttributePair join = (DbAttributePair) joins.get(0);
! DbAttribute att = null;
! if (rel.isToMany()) {
! DbEntity ent = (DbEntity) join.getTarget().getEntity();
! List pk = ent.getPrimaryKey();
! if (pk.size() != 1) {
! StringBuffer msg = new StringBuffer();
! msg
! .append("DB_NAME expressions can only support ")
! .append("targets with a single column PK. ")
! .append("This entity has ")
! .append(pk.size())
! .append(" columns in primary key.");
! throw new CayenneRuntimeException(msg.toString());
! }
! att = (DbAttribute) pk.get(0);
! } else {
! att = join.getSource();
! }
! processColumn(buf, att);
! }
}
Index: SelectTranslator.java
===================================================================
RCS file: /cvsroot/cayenne/cayenne/src/cayenne/java/org/objectstyle/cayenne/access/trans/SelectTranslator.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** SelectTranslator.java 8 Sep 2002 22:46:47 -0000 1.1
--- SelectTranslator.java 1 Oct 2002 02:07:39 -0000 1.2
***************
*** 74,490 ****
*/
public class SelectTranslator extends SelectQueryAssembler {
! static Logger logObj = Logger.getLogger(SelectTranslator.class.getName());
!
! private final HashMap aliasLookup = new HashMap();
! private final ArrayList columnList = new ArrayList();
! private final ArrayList tableList = new ArrayList();
! private final ArrayList aliasList = new ArrayList();
! private final ArrayList dbRelList = new ArrayList();
! private List groupByList;
! private int aliasCounter;
! /**
! * If set to <code>true</code>, indicates that distinct
! * select query is required no matter what the original query
! * settings where. This flag can be set when joins are created
! * using "to-many" relationships.
! */
! private boolean forceDistinct;
! /**
! * Returns a list of DbAttributes representing columns
! * in this query.
! */
! protected List getColumnList() {
! return columnList;
! }
! public int getFetchLimit() {
! return getSelectQuery().getFetchLimit();
! }
! /**
! * Returns an ordered list of DbAttributes that describe the
! * result columns in the in the ResultSet. ResultSet column names are ignored,
! * names specified in the query are used instead. */
! public DbAttribute[] getSnapshotDesc(ResultSet rs) {
! int len = columnList.size();
! if (len == 0) {
! throw new CayenneRuntimeException("Call 'createStatement' first");
! }
!
! DbAttribute[] desc = new DbAttribute[len];
! columnList.toArray(desc);
! return desc;
! }
! /**
! * Returns ordered list of Java class names that should be used for fetched values.
! * ResultSet types are ignored, types specified in the query are used instead.
! */
! public String[] getResultTypes(ResultSet rs) {
! int len = columnList.size();
! if (len == 0) {
! throw new CayenneRuntimeException("Call 'createStatement' first.");
! }
! String[] types = new String[len];
! for (int i = 0; i < len; i++) {
! DbAttribute attr = (DbAttribute) columnList.get(i);
! ObjAttribute objAttr =
! getRootEntity().getAttributeForDbAttribute(attr);
! // use explicit type mapping specified in ObjAttribute,
! // or use default JDBC mapping if no ObjAttribute exists
! types[i] =
! (objAttr != null)
! ? objAttr.getType()
! : TypesMapping.getJavaBySqlType(attr.getType());
! }
! return types;
! }
! /**
! * Returns query translated to SQL. This is a main work method of the SelectTranslator.
! */
! public String createSqlString() throws Exception {
! forceDistinct = false;
! // build column list
! buildColumnList();
! QualifierTranslator tr =
! adapter.getQualifierFactory().createTranslator(this);
! // build parent qualifier
! // Parent qualifier translation must PRECEED main qualifier
! // since it will be appended first and its parameters must
! // go first as well
! String parentQualifierStr = null;
! if (getSelectQuery().isQualifiedOnParent()) {
! tr.setTranslateParentQual(true);
! parentQualifierStr = tr.doTranslation();
! }
! // build main qualifier
! tr.setTranslateParentQual(false);
! String qualifierStr = tr.doTranslation();
! // build GROUP BY
! buildGroupByList();
! // build ORDER BY,
! String orderByStr = new OrderingTranslator(this).doTranslation();
! // assemble
! StringBuffer queryBuf = new StringBuffer();
! queryBuf.append("SELECT ");
! if (forceDistinct || getSelectQuery().isDistinct()) {
! queryBuf.append("DISTINCT ");
! }
! // append columns (unroll the loop's first element)
! int columnCount = columnList.size();
! appendColumn(queryBuf, 0); // assume there is at least 1 element
! for (int i = 1; i < columnCount; i++) {
! queryBuf.append(", ");
! appendColumn(queryBuf, i);
! }
! // append from clause
! queryBuf.append(" FROM ");
! // append table list (unroll loop's 1st element)
! int tableCount = tableList.size();
! appendTable(queryBuf, 0); // assume there is at least 1 table
! for (int i = 1; i < tableCount; i++) {
! queryBuf.append(", ");
! appendTable(queryBuf, i);
! }
! // append db relationship joins if any
! boolean hasWhere = false;
! int dbRelCount = dbRelList.size();
! if (dbRelCount > 0) {
! hasWhere = true;
! queryBuf.append(" WHERE ");
! appendDbRelJoins(queryBuf, 0);
! for (int i = 1; i < dbRelCount; i++) {
! queryBuf.append(" AND ");
! appendDbRelJoins(queryBuf, i);
! }
! }
! // append parent qualifier if any
! if (parentQualifierStr != null) {
! if (hasWhere) {
! queryBuf.append(" AND (");
! queryBuf.append(parentQualifierStr);
! queryBuf.append(")");
! } else {
! hasWhere = true;
! queryBuf.append(" WHERE ");
! queryBuf.append(parentQualifierStr);
! }
! }
! // append group by
! boolean hasGroupBy = false;
! if (groupByList != null) {
! int groupByCount = groupByList.size();
! if (groupByCount > 0) {
! hasGroupBy = true;
! queryBuf.append(" GROUP BY ");
! appendGroupBy(queryBuf, 0);
! for (int i = 1; i < groupByCount; i++) {
! queryBuf.append(", ");
! appendGroupBy(queryBuf, i);
! }
! }
! }
! // append qualifier
! if (qualifierStr != null) {
! if (hasGroupBy) {
! queryBuf.append(" HAVING ");
! queryBuf.append(qualifierStr);
! } else {
! if (hasWhere) {
! queryBuf.append(" AND (");
! queryBuf.append(qualifierStr);
! queryBuf.append(")");
! } else {
! hasWhere = true;
! queryBuf.append(" WHERE ");
! queryBuf.append(qualifierStr);
! }
! }
! }
! // append prebuilt ordering
! if (orderByStr != null) {
! queryBuf.append(" ORDER BY ").append(orderByStr);
! }
! return queryBuf.toString();
! }
! private SelectQuery getSelectQuery() {
! return (SelectQuery) getQuery();
! }
! /**
! * Creates a list of columns used in the query.
! */
! private void buildColumnList() {
! newAliasForTable(getRootEntity().getDbEntity());
! appendAttributes();
! }
! /**
! * Creates a list of columns used in the query's GROUP BY clause.
! */
! private void buildGroupByList() {
! DbEntity dbEntity = getRootEntity().getDbEntity();
! if (dbEntity instanceof DerivedDbEntity) {
! groupByList = ((DerivedDbEntity) dbEntity).getGroupByAttributes();
! }
! }
! /**
! * Returns a list of DbAttributes used in query.
! */
! private void appendAttributes() {
! ObjEntity oe = getRootEntity();
! DbEntity dbe = oe.getDbEntity();
! SelectQuery q = getSelectQuery();
! // extract custom attributes from the query
! if (q.isFetchingCustAttributes()) {
! List custAttrNames = q.getCustDbAttributes();
! int len = custAttrNames.size();
! for (int i = 0; i < len; i++) {
! Attribute attr =
! dbe.getAttribute((String) custAttrNames.get(i));
! if (attr == null) {
! throw new CayenneRuntimeException(
! "Attribute does not exist: " + custAttrNames.get(i));
! }
! columnList.add(attr);
! }
! } else {
! // build a list of attributes mentioned in ObjEntity + PK's + FK's + GROUP BY's
! // ObjEntity attrs
! List attrs = oe.getAttributeList();
! int len = attrs.size();
! for (int i = 0; i < len; i++) {
! ObjAttribute oa = (ObjAttribute) attrs.get(i);
! Attribute dbAttr = oa.getDbAttribute();
! if (dbAttr == null) {
! throw new CayenneRuntimeException(
! "ObjAttribute has no DbAttribute: " + oa.getName());
! }
! columnList.add(dbAttr);
! }
! // relationship keys
! List rels = oe.getRelationshipList();
! int rLen = rels.size();
! for (int i = 0; i < rLen; i++) {
! ObjRelationship rel = (ObjRelationship) rels.get(i);
! DbRelationship dbRel =
! (DbRelationship) rel.getDbRelationshipList().get(0);
! List joins = dbRel.getJoins();
! int jLen = joins.size();
! for (int j = 0; j < jLen; j++) {
! DbAttributePair join = (DbAttributePair) joins.get(j);
! DbAttribute src = join.getSource();
! if (!columnList.contains(src)) {
! columnList.add(src);
! }
! }
! }
! // add remaining needed attrs from DbEntity
! List dbattrs = dbe.getAttributeList();
! int dLen = dbattrs.size();
! for (int i = 0; i < dLen; i++) {
! DbAttribute dba = (DbAttribute) dbattrs.get(i);
! if (dba.isPrimaryKey()) {
! if (!columnList.contains(dba)) {
! columnList.add(dba);
! }
! }
! }
! }
! }
! private void appendColumn(StringBuffer queryBuf, int index) {
! DbAttribute attr = (DbAttribute) columnList.get(index);
! String alias = aliasForTable((DbEntity) attr.getEntity());
! queryBuf.append(attr.getAliasedName(alias));
! }
! private void appendGroupBy(StringBuffer queryBuf, int index) {
! DbAttribute attr = (DbAttribute) groupByList.get(index);
! DbEntity ent = (DbEntity)attr.getEntity();
! queryBuf.append(
! attr.getAliasedName(aliasForTable(ent)));
! }
! private void appendTable(StringBuffer queryBuf, int index) {
! DbEntity ent = (DbEntity) tableList.get(index);
! queryBuf.append(ent.getFullyQualifiedName());
! queryBuf.append(' ').append(aliasForTable(ent));
! }
! private void appendDbRelJoins(StringBuffer queryBuf, int index) {
! DbRelationship rel = (DbRelationship) dbRelList.get(index);
! String srcAlias = aliasForTable((DbEntity) rel.getSourceEntity());
! String targetAlias = aliasForTable((DbEntity) rel.getTargetEntity());
! boolean andFlag = false;
! List joins = rel.getJoins();
! int len = joins.size();
! for (int i = 0; i < len; i++) {
! if (andFlag)
! queryBuf.append(" AND ");
! else
! andFlag = true;
! DbAttributePair join = (DbAttributePair) joins.get(i);
! DbAttribute src = join.getSource();
! queryBuf
! .append(srcAlias)
! .append('.')
! .append(join.getSource().getName())
! .append(" = ")
! .append(targetAlias)
! .append('.')
! .append(join.getTarget().getName());
! }
! }
! /**
! * Stores a new relationship in an internal list.
! * Later it will be used to create joins to relationship
! * destination table.
! */
! public void dbRelationshipAdded(DbRelationship rel) {
! if (rel.isToMany()) {
! forceDistinct = true;
! }
! String existAlias = (String) aliasLookup.get(rel);
! if (existAlias == null) {
! dbRelList.add(rel);
! // add alias for the destination table of the relationship
! String newAlias =
! newAliasForTable((DbEntity) rel.getTargetEntity());
! aliasLookup.put(rel, newAlias);
! }
! }
! /**
! * Sets up and returns a new alias for a speciafied table.
! */
! protected String newAliasForTable(DbEntity ent) {
! if (ent instanceof DerivedDbEntity) {
! ent = ((DerivedDbEntity) ent).getParentEntity();
! }
! String newAlias = "t" + aliasCounter++;
! tableList.add(ent);
! aliasList.add(newAlias);
! return newAlias;
! }
! /**
! * Overrides superclass implementation. Will return an alias that
! * should be used for a specified DbEntity in the query
! * (or null if this DbEntity is not included in the FROM clause).
! */
! public String aliasForTable(DbEntity ent) {
! if (ent instanceof DerivedDbEntity) {
! ent = ((DerivedDbEntity) ent).getParentEntity();
! }
! int entIndex = tableList.indexOf(ent);
! if (entIndex >= 0) {
! return (String) aliasList.get(entIndex);
! } else {
! StringBuffer msg = new StringBuffer();
! msg
! .append("Alias not found, DbEntity: '")
! .append(ent != null ? ent.getName() : "<null entity>")
! .append("'\nExisting aliases:");
! int len = aliasList.size();
! for (int i = 0; i < len; i++) {
! String dbeName =
! (tableList.get(i) != null)
! ? ((DbEntity) tableList.get(i)).getName()
! : "<null entity>";
! msg.append("\n").append(aliasList.get(0)).append(
! " => ").append(
! dbeName);
! }
! throw new CayenneRuntimeException(msg.toString());
! }
! }
! public boolean supportsTableAliases() {
! return true;
! }
}
--- 74,486 ----
*/
public class SelectTranslator extends SelectQueryAssembler {
! static Logger logObj = Logger.getLogger(SelectTranslator.class.getName());
! private final HashMap aliasLookup = new HashMap();
! private final ArrayList columnList = new ArrayList();
! private final ArrayList tableList = new ArrayList();
! private final ArrayList aliasList = new ArrayList();
! private final ArrayList dbRelList = new ArrayList();
! private List groupByList;
! private int aliasCounter;
! /**
! * If set to <code>true</code>, indicates that distinct
! * select query is required no matter what the original query
! * settings where. This flag can be set when joins are created
! * using "to-many" relationships.
! */
! private boolean forceDistinct;
! /**
! * Returns a list of DbAttributes representing columns
! * in this query.
! */
! protected List getColumnList() {
! return columnList;
! }
! public int getFetchLimit() {
! return getSelectQuery().getFetchLimit();
! }
! /**
! * Returns an ordered list of DbAttributes that describe the
! * result columns in the in the ResultSet. ResultSet column names are ignored,
! * names specified in the query are used instead. */
! public DbAttribute[] getSnapshotDesc(ResultSet rs) {
! int len = columnList.size();
! if (len == 0) {
! throw new CayenneRuntimeException("Call 'createStatement' first");
! }
! DbAttribute[] desc = new DbAttribute[len];
! columnList.toArray(desc);
! return desc;
! }
! /**
! * Returns ordered list of Java class names that should be used for fetched values.
! * ResultSet types are ignored, types specified in the query are used instead.
! */
! public String[] getResultTypes(ResultSet rs) {
! int len = columnList.size();
! if (len == 0) {
! throw new CayenneRuntimeException("Call 'createStatement' first.");
! }
! String[] types = new String[len];
! for (int i = 0; i < len; i++) {
! DbAttribute attr = (DbAttribute) columnList.get(i);
! ObjAttribute objAttr = getRootEntity().getAttributeForDbAttribute(attr);
! // use explicit type mapping specified in ObjAttribute,
! // or use default JDBC mapping if no ObjAttribute exists
! types[i] =
! (objAttr != null)
! ? objAttr.getType()
! : TypesMapping.getJavaBySqlType(attr.getType());
! }
! return types;
! }
! /**
! * Returns query translated to SQL. This is a main work method of the SelectTranslator.
! */
! public String createSqlString() throws Exception {
! forceDistinct = false;
! // build column list
! buildColumnList();
! QualifierTranslator tr = adapter.getQualifierFactory().createTranslator(this);
! // build parent qualifier
! // Parent qualifier translation must PRECEED main qualifier
! // since it will be appended first and its parameters must
! // go first as well
! String parentQualifierStr = null;
! if (getSelectQuery().isQualifiedOnParent()) {
! tr.setTranslateParentQual(true);
! parentQualifierStr = tr.doTranslation();
! }
! // build main qualifier
! tr.setTranslateParentQual(false);
! String qualifierStr = tr.doTranslation();
! // build GROUP BY
! buildGroupByList();
! // build ORDER BY,
! String orderByStr = new OrderingTranslator(this).doTranslation();
! // assemble
! StringBuffer queryBuf = new StringBuffer();
! queryBuf.append("SELECT ");
! if (forceDistinct || getSelectQuery().isDistinct()) {
! queryBuf.append("DISTINCT ");
! }
! // append columns (unroll the loop's first element)
! int columnCount = columnList.size();
! appendColumn(queryBuf, 0); // assume there is at least 1 element
! for (int i = 1; i < columnCount; i++) {
! queryBuf.append(", ");
! appendColumn(queryBuf, i);
! }
! // append from clause
! queryBuf.append(" FROM ");
! // append table list (unroll loop's 1st element)
! int tableCount = tableList.size();
! appendTable(queryBuf, 0); // assume there is at least 1 table
! for (int i = 1; i < tableCount; i++) {
! queryBuf.append(", ");
! appendTable(queryBuf, i);
! }
! // append db relationship joins if any
! boolean hasWhere = false;
! int dbRelCount = dbRelList.size();
! if (dbRelCount > 0) {
! hasWhere = true;
! queryBuf.append(" WHERE ");
! appendDbRelJoins(queryBuf, 0);
! for (int i = 1; i < dbRelCount; i++) {
! queryBuf.append(" AND ");
! appendDbRelJoins(queryBuf, i);
! }
! }
! // append parent qualifier if any
! if (parentQualifierStr != null) {
! if (hasWhere) {
! queryBuf.append(" AND (");
! queryBuf.append(parentQualifierStr);
! queryBuf.append(")");
! } else {
! hasWhere = true;
! queryBuf.append(" WHERE ");
! queryBuf.append(parentQualifierStr);
! }
! }
! // append group by
! boolean hasGroupBy = false;
! if (groupByList != null) {
! int groupByCount = groupByList.size();
! if (groupByCount > 0) {
! hasGroupBy = true;
! queryBuf.append(" GROUP BY ");
! appendGroupBy(queryBuf, 0);
! for (int i = 1; i < groupByCount; i++) {
! queryBuf.append(", ");
! appendGroupBy(queryBuf, i);
! }
! }
! }
! // append qualifier
! if (qualifierStr != null) {
! if (hasGroupBy) {
! queryBuf.append(" HAVING ");
! queryBuf.append(qualifierStr);
! } else {
! if (hasWhere) {
! queryBuf.append(" AND (");
! queryBuf.append(qualifierStr);
! queryBuf.append(")");
! } else {
! hasWhere = true;
! queryBuf.append(" WHERE ");
! queryBuf.append(qualifierStr);
! }
! }
! }
! // append prebuilt ordering
! if (orderByStr != null) {
! queryBuf.append(" ORDER BY ").append(orderByStr);
! }
! return queryBuf.toString();
! }
! private SelectQuery getSelectQuery() {
! return (SelectQuery) getQuery();
! }
! /**
! * Creates a list of columns used in the query.
! */
! private void buildColumnList() {
! newAliasForTable(getRootEntity().getDbEntity());
! appendAttributes();
! }
! /**
! * Creates a list of columns used in the query's GROUP BY clause.
! */
! private void buildGroupByList() {
! DbEntity dbEntity = getRootEntity().getDbEntity();
! if (dbEntity instanceof DerivedDbEntity) {
! groupByList = ((DerivedDbEntity) dbEntity).getGroupByAttributes();
! }
! }
! /**
! * Returns a list of DbAttributes used in query.
! */
! private void appendAttributes() {
! ObjEntity oe = getRootEntity();
! DbEntity dbe = oe.getDbEntity();
! SelectQuery q = getSelectQuery();
! // extract custom attributes from the query
! if (q.isFetchingCustAttributes()) {
! List custAttrNames = q.getCustDbAttributes();
! int len = custAttrNames.size();
! for (int i = 0; i < len; i++) {
! Attribute attr = dbe.getAttribute((String) custAttrNames.get(i));
! if (attr == null) {
! throw new CayenneRuntimeException(
! "Attribute does not exist: " + custAttrNames.get(i));
! }
! columnList.add(attr);
! }
! } else {
! // build a list of attributes mentioned in ObjEntity + PK's + FK's + GROUP BY's
! // ObjEntity attrs
! List attrs = oe.getAttributeList();
! int len = attrs.size();
! for (int i = 0; i < len; i++) {
! ObjAttribute oa = (ObjAttribute) attrs.get(i);
! Attribute dbAttr = oa.getDbAttribute();
! if (dbAttr == null) {
! throw new CayenneRuntimeException(
! "ObjAttribute has no DbAttribute: " + oa.getName());
! }
! columnList.add(dbAttr);
! }
! // relationship keys
! List rels = oe.getRelationshipList();
! int rLen = rels.size();
! for (int i = 0; i < rLen; i++) {
! ObjRelationship rel = (ObjRelationship) rels.get(i);
! DbRelationship dbRel =
! (DbRelationship) rel.getDbRelationshipList().get(0);
! List joins = dbRel.getJoins();
! int jLen = joins.size();
! for (int j = 0; j < jLen; j++) {
! DbAttributePair join = (DbAttributePair) joins.get(j);
! DbAttribute src = join.getSource();
! if (!columnList.contains(src)) {
! columnList.add(src);
! }
! }
! }
+ // add remaining needed attrs from DbEntity
+ List dbattrs = dbe.getAttributeList();
+ int dLen = dbattrs.size();
+ for (int i = 0; i < dLen; i++) {
+ DbAttribute dba = (DbAttribute) dbattrs.get(i);
+ if (dba.isPrimaryKey()) {
+ if (!columnList.contains(dba)) {
+ columnList.add(dba);
+ }
+ }
+ }
+ }
+ }
! private void appendColumn(StringBuffer queryBuf, int index) {
! DbAttribute attr = (DbAttribute) columnList.get(index);
! String alias = aliasForTable((DbEntity) attr.getEntity());
! queryBuf.append(attr.getAliasedName(alias));
! }
+ private void appendGroupBy(StringBuffer queryBuf, int index) {
+ DbAttribute attr = (DbAttribute) groupByList.get(index);
+ DbEntity ent = (DbEntity) attr.getEntity();
+ queryBuf.append(attr.getAliasedName(aliasForTable(ent)));
+ }
! private void appendTable(StringBuffer queryBuf, int index) {
! DbEntity ent = (DbEntity) tableList.get(index);
! queryBuf.append(ent.getFullyQualifiedName());
! //The alias should be the alias from the same index in aliasList, not that
! // returned by aliasForTable.
! queryBuf.append(' ').append((String) aliasList.get(index));
! }
+ private void appendDbRelJoins(StringBuffer queryBuf, int index) {
+ DbRelationship rel = (DbRelationship) dbRelList.get(index);
+ String srcAlias = aliasForTable((DbEntity) rel.getSourceEntity());
+ String targetAlias = (String) aliasLookup.get(rel);
! boolean andFlag = false;
! List joins = rel.getJoins();
! int len = joins.size();
! for (int i = 0; i < len; i++) {
! if (andFlag)
! queryBuf.append(" AND ");
! else
! andFlag = true;
! DbAttributePair join = (DbAttributePair) joins.get(i);
! DbAttribute src = join.getSource();
! queryBuf
! .append(srcAlias)
! .append('.')
! .append(join.getSource().getName())
! .append(" = ")
! .append(targetAlias)
! .append('.')
! .append(join.getTarget().getName());
! }
! }
! /**
! * Stores a new relationship in an internal list.
! * Later it will be used to create joins to relationship
! * destination table.
! */
! public void dbRelationshipAdded(DbRelationship rel) {
! if (rel.isToMany()) {
! forceDistinct = true;
! }
! String existAlias = (String) aliasLookup.get(rel);
! if (existAlias == null) {
! dbRelList.add(rel);
! // add alias for the destination table of the relationship
! String newAlias = newAliasForTable((DbEntity) rel.getTargetEntity());
! aliasLookup.put(rel, newAlias);
! }
! }
! /**
! * Sets up and returns a new alias for a speciafied table.
! */
! protected String newAliasForTable(DbEntity ent) {
! if (ent instanceof DerivedDbEntity) {
! ent = ((DerivedDbEntity) ent).getParentEntity();
! }
! String newAlias = "t" + aliasCounter++;
! tableList.add(ent);
! aliasList.add(newAlias);
! return newAlias;
! }
! public String aliasForTable(DbEntity ent, DbRelationship rel) {
! return (String) aliasLookup.get(rel);
! }
! /**
! * Overrides superclass implementation. Will return an alias that
! * should be used for a specified DbEntity in the query
! * (or null if this DbEntity is not included in the FROM clause).
! */
! public String aliasForTable(DbEntity ent) {
! if (ent instanceof DerivedDbEntity) {
! ent = ((DerivedDbEntity) ent).getParentEntity();
! }
! int entIndex = tableList.indexOf(ent);
! if (entIndex >= 0) {
! return (String) aliasList.get(entIndex);
! } else {
! StringBuffer msg = new StringBuffer();
! msg
! .append("Alias not found, DbEntity: '")
! .append(ent != null ? ent.getName() : "<null entity>")
! .append("'\nExisting aliases:");
! int len = aliasList.size();
! for (int i = 0; i < len; i++) {
! String dbeName =
! (tableList.get(i) != null)
! ? ((DbEntity) tableList.get(i)).getName()
! : "<null entity>";
! msg.append("\n").append(aliasList.get(0)).append(" => ").append(dbeName);
! }
! throw new CayenneRuntimeException(msg.toString());
! }
! }
! public boolean supportsTableAliases() {
! return true;
! }
}
|
|
From: <me...@us...> - 2002-09-26 04:10:52
|
Update of /cvsroot/cayenne/cayenne In directory usw-pr-cvs1:/tmp/cvs-serv17505 Modified Files: build.xml Log Message: testing cvs updates Index: build.xml =================================================================== RCS file: /cvsroot/cayenne/cayenne/build.xml,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -d -r1.38 -r1.39 *** build.xml 24 Sep 2002 15:30:49 -0000 1.38 --- build.xml 26 Sep 2002 04:10:48 -0000 1.39 *************** *** 1,5 **** <?xml version="1.0"?> - <!-- ================================================= --> <!-- Cayenne master build file. --> --- 1,4 ---- |