Author: brj
Date: Fri Jan 27 11:00:27 2006
New Revision: 372946
URL: http://svn.apache.org/viewcvs?rev=372946&view=rev
Log:
Better support for attributes containing expressions ie. sum(0.9 * price *
stock)
Backport from OJB 1.x
Modified:
db/ojb/branches/OJB_1_0_RELEASE/release-notes.txt
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlDeleteByQuery.java
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/SqlHelper.java
db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/QueryTest.java
Modified: db/ojb/branches/OJB_1_0_RELEASE/release-notes.txt
URL:
http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/release-notes.txt?rev=372946&r1=372945&r2=372946&view=diff
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/release-notes.txt (original)
+++ db/ojb/branches/OJB_1_0_RELEASE/release-notes.txt Fri Jan 27 11:00:27 2006
@@ -18,6 +18,8 @@
Release 1.0.5
---------------------------------------------------------------------
NEW FEATURES:
+- Better support for attributes containing expressions ie. sum(0.9 * price *
stock).
+ Restriction: All attributes contained in the expressions have to belong to
the same table !
NOTES:
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlDeleteByQuery.java
URL:
http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlDeleteByQuery.java?rev=372946&r1=372945&r2=372946&view=diff
==============================================================================
---
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlDeleteByQuery.java
(original)
+++
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlDeleteByQuery.java
Fri Jan 27 11:00:27 2006
@@ -16,11 +16,9 @@
*/
import org.apache.ojb.broker.metadata.ClassDescriptor;
-import org.apache.ojb.broker.metadata.FieldDescriptor;
import org.apache.ojb.broker.platforms.Platform;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.Query;
-import org.apache.ojb.broker.util.SqlHelper.PathInfo;
import org.apache.ojb.broker.util.logging.Logger;
/**
@@ -58,30 +56,17 @@
return stmt.toString();
}
- /* (non-Javadoc)
- * @see
org.apache.ojb.broker.accesslayer.sql.SqlQueryStatement#getColName(org.apache.ojb.broker.accesslayer.sql.SqlQueryStatement.TableAlias,
org.apache.ojb.broker.util.SqlHelper.PathInfo, boolean)
- */
- protected String getColName(TableAlias aTableAlias, PathInfo aPathInfo,
boolean translate)
- {
- FieldDescriptor fld = null;
- String result;
-
- if (translate)
- {
- fld = getFieldDescriptor(aTableAlias, aPathInfo);
- }
-
- if (fld != null)
- {
- // BRJ : No alias for delete
- result = fld.getColumnName();
- }
- else
- {
- result = aPathInfo.column;
- }
-
- return result;
- }
+ /**
+ * Append a Column with alias: A0 name -> A0.name
+ * Do NOT use an alias here.
+ * @param anAlias the TableAlias
+ * @param aColumn name
+ * @param buf
+ */
+ protected void appendColumn(TableAlias anAlias, String aColumn,
StringBuffer buf)
+ {
+ // BRJ : No alias for delete
+ buf.append(aColumn);
+ }
}
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
URL:
http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java?rev=372946&r1=372945&r2=372946&view=diff
==============================================================================
---
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
(original)
+++
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlQueryStatement.java
Fri Jan 27 11:00:27 2006
@@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.StringTokenizer;
import org.apache.ojb.broker.PersistenceBrokerSQLException;
import org.apache.ojb.broker.accesslayer.JoinSyntaxTypes;
@@ -37,7 +38,6 @@
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.ExistsCriteria;
import org.apache.ojb.broker.query.FieldCriteria;
-import org.apache.ojb.broker.query.InCriteria;
import org.apache.ojb.broker.query.InCriterion;
import org.apache.ojb.broker.query.LikeCriteria;
import org.apache.ojb.broker.query.MtoNQuery;
@@ -49,7 +49,6 @@
import org.apache.ojb.broker.query.SqlCriteria;
import org.apache.ojb.broker.query.UserAlias;
import org.apache.ojb.broker.util.SqlHelper;
-import org.apache.ojb.broker.util.SqlHelper.PathInfo;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
@@ -170,43 +169,83 @@
return m_searchCld;
}
+ /**
+ * Get the Attribute info of an attribute. The attribute may be a simple
name (ie. price) or it
+ * may be an expression containing functions or other attributes (ie.
sum(price * stock) ).<br>
+ * <b>All embedded attributes must be of the same table !</b>
+ * <br>
+ * The exploded path contains Strings for the tokens and functions and
+ * SingleAttributeInfo for the attributes.<br>
+ * ie: 0.9 * (price * stock) the attributes price and stock are wrapped
+ * in SingleAttributeInfo the whole rest are Strings
+ * <pre>
+ * [0.9, * , ( sai(price), * , sai(stock), )]
+ * </pre>
+ * The attribute infos are cached for later use.
+ *
+ * @param attr the attribute or expression
+ * @param useOuterJoins
+ * @param aUserAlias
+ * @param pathClasses
+ * @return the AttributeInfo of the attribute or expression
+ */
+ protected AttributeInfo getAttributeInfo(String attr, boolean
useOuterJoins, UserAlias aUserAlias, Map pathClasses)
+ {
+ AttributeInfo result = new AttributeInfo(attr);
+
+ StringTokenizer st = SqlHelper.tokenizeAttribute(attr);
+ result = new AttributeInfo(attr);
+
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if (SqlHelper.isAttribute(token))
+ {
+ result.add(getSingleAttributeInfo(token, useOuterJoins,
aUserAlias, pathClasses));
+ }
+ else
+ {
+ result.add(token);
+ }
+ }
+
+ return result;
+ }
+
/**
* Return the TableAlias and the PathInfo for an Attribute name<br>
* field names in functions (ie: sum(name) ) are tried to resolve ie:
name
* from FIELDDESCRIPTOR , UPPER(name_test) from Criteria<br>
* also resolve pathExpression adress.city or owner.konti.saldo
- * @param attr
+ * @param attrName
* @param useOuterJoins
* @param aUserAlias
* @param pathClasses
* @return ColumnInfo
*/
- protected AttributeInfo getAttributeInfo(String attr, boolean
useOuterJoins, UserAlias aUserAlias, Map pathClasses)
+ protected SingleAttributeInfo getSingleAttributeInfo(String attrName,
boolean useOuterJoins, UserAlias aUserAlias, Map pathClasses)
{
- AttributeInfo result = new AttributeInfo();
TableAlias tableAlias;
- SqlHelper.PathInfo pathInfo = SqlHelper.splitPath(attr);
- String colName = pathInfo.column;
int sp;
// BRJ:
// check if we refer to an attribute in the parent query
// this prefix is temporary !
- if (colName.startsWith(Criteria.PARENT_QUERY_PREFIX) &&
m_parentStatement != null)
+ if (attrName.startsWith(Criteria.PARENT_QUERY_PREFIX) &&
m_parentStatement != null)
{
- String[] fieldNameRef =
{colName.substring(Criteria.PARENT_QUERY_PREFIX.length())};
- return
m_parentStatement.getAttributeInfo(fieldNameRef[0], useOuterJoins, aUserAlias,
pathClasses);
+ String[] fieldNameRef =
{attrName.substring(Criteria.PARENT_QUERY_PREFIX.length())};
+ return
m_parentStatement.getSingleAttributeInfo(fieldNameRef[0], useOuterJoins,
aUserAlias, pathClasses);
}
- sp = colName.lastIndexOf(".");
+ sp = attrName.lastIndexOf(".");
if (sp == -1)
{
tableAlias = getRoot();
}
else
{
- String pathName = colName.substring(0, sp);
- String[] fieldNameRef = {colName.substring(sp + 1)};
+ String pathName = attrName.substring(0, sp);
+ String[] fieldNameRef = {attrName.substring(sp + 1)};
tableAlias = getTableAlias(pathName, useOuterJoins,
aUserAlias, fieldNameRef, pathClasses);
/**
@@ -216,12 +255,11 @@
* a path, which means there may be no path separators
(,)
* in the pathName.
*/
- if ((tableAlias == null) && (colName.lastIndexOf(".")
== -1))
+ if ((tableAlias == null) && (attrName.lastIndexOf(".")
== -1))
{
/**
* pathName might be an alias, so check this
first
*/
-// tableAlias = getTableAlias(pathName,
useOuterJoins, new UserAlias(pathName, pathName, pathName), null, pathClasses);
tableAlias = getTableAlias(pathName, useOuterJoins,
aUserAlias, null, pathClasses);
}
@@ -229,136 +267,111 @@
{
// correct column name to match the alias
// productGroup.groupName -> groupName
- pathInfo.column = fieldNameRef[0];
+ attrName = fieldNameRef[0];
}
}
- result.tableAlias = tableAlias;
- result.pathInfo = pathInfo;
- return result;
+ return new SingleAttributeInfo(tableAlias, attrName);
}
/**
- * Answer the column name for alias and path info<br>
- * if translate try to convert attribute name into column name otherwise
use attribute name<br>
- * if a FieldDescriptor is found for the attribute name the column name is
taken from
- * there prefixed with the alias (firstname -> A0.F_NAME).
+ * Add the Column to the StringBuffer <br>
+ *
+ * @param aTableAlias
+ * @param aPathInfo
+ * @param translate flag to indicate translation of pathInfo
+ * @param buf
*/
- protected String getColName(TableAlias aTableAlias, PathInfo aPathInfo,
boolean translate)
+ protected void appendColumn(SingleAttributeInfo anAttrInfo, boolean
translate, StringBuffer buf)
{
- String result = null;
+ TableAlias tableAlias = anAttrInfo.getTableAlias();
+ String colName = anAttrInfo.getAttribute();
// no translation required, use attribute name
if (!translate)
{
- return aPathInfo.column;
+ buf.append(colName);
+ return;
}
// BRJ: special alias for the indirection table has no ClassDescriptor
- if (aTableAlias.cld == null && M_N_ALIAS.equals(aTableAlias.alias))
+ if (tableAlias != null && tableAlias.cld == null &&
M_N_ALIAS.equals(tableAlias.alias))
{
- return getIndirectionTableColName(aTableAlias, aPathInfo.path);
+ appendColumn(tableAlias, colName, buf);
+ return;
}
// translate attribute name into column name
- FieldDescriptor fld = getFieldDescriptor(aTableAlias, aPathInfo);
+ FieldDescriptor fld = getFieldDescriptor(tableAlias, colName);
- if (fld != null)
+ if (fld == null)
{
- m_attrToFld.put(aPathInfo.path, fld);
+ buf.append(colName);
+ return;
+ }
- // added to suport the super reference descriptor
- if
(!fld.getClassDescriptor().getFullTableName().equals(aTableAlias.table) &&
aTableAlias.hasJoins())
- {
- Iterator itr = aTableAlias.joins.iterator();
- while (itr.hasNext())
- {
- Join join = (Join) itr.next();
- if
(join.right.table.equals(fld.getClassDescriptor().getFullTableName()))
- {
- result = join.right.alias + "." + fld.getColumnName();
- break;
- }
- }
+ m_attrToFld.put(anAttrInfo.getParent().getAttribute(), fld);
- if (result == null)
+ // added to suport the super reference descriptor
+ if
(!fld.getClassDescriptor().getFullTableName().equals(tableAlias.table) &&
tableAlias.hasJoins())
+ {
+ Iterator itr = tableAlias.joins.iterator();
+ while (itr.hasNext())
+ {
+ Join join = (Join) itr.next();
+ if
(join.right.table.equals(fld.getClassDescriptor().getFullTableName()))
{
- result = aPathInfo.column;
+ tableAlias = join.right;
+ colName = fld.getColumnName();
+ break;
}
}
- else
- {
- result = aTableAlias.alias + "." + fld.getColumnName();
- }
- }
- else if ("*".equals(aPathInfo.column))
- {
- result = aPathInfo.column;
}
else
{
- // throw new IllegalArgumentException("No Field found for : " +
aPathInfo.column);
- result = aPathInfo.column;
+ colName = fld.getColumnName();
}
- return result;
+ appendColumn(tableAlias, colName, buf);
}
/**
- * Add the Column to the StringBuffer <br>
- *
- * @param aTableAlias
- * @param aPathInfo
- * @param translate flag to indicate translation of pathInfo
+ * Append a Column with alias: A0 name -> A0.name
+ * @param anAlias the TableAlias
+ * @param aColumn name
* @param buf
- * @return true if appended
*/
- protected boolean appendColName(TableAlias aTableAlias, PathInfo
aPathInfo, boolean translate, StringBuffer buf)
+ protected void appendColumn(TableAlias anAlias, String aColumn,
StringBuffer buf)
{
- String prefix = aPathInfo.prefix;
- String suffix = aPathInfo.suffix;
- String colName = getColName(aTableAlias, aPathInfo, translate);
-
- if (prefix != null) // rebuild function contains (
- {
- buf.append(prefix);
- }
-
- buf.append(colName);
-
- if (suffix != null) // rebuild function
- {
- buf.append(suffix);
- }
-
- return true;
+ buf.append(anAlias.alias);
+ buf.append(".");
+ buf.append(aColumn);
}
-
+
/**
* Get the FieldDescriptor for the PathInfo
*
* @param aTableAlias
- * @param aPathInfo
+ * @param anAttrName
* @return FieldDescriptor
*/
- protected FieldDescriptor getFieldDescriptor(TableAlias aTableAlias,
PathInfo aPathInfo)
+ protected FieldDescriptor getFieldDescriptor(TableAlias aTableAlias,
String anAttrName)
{
FieldDescriptor fld = null;
- String colName = aPathInfo.column;
if (aTableAlias != null)
{
- fld = aTableAlias.cld.getFieldDescriptorByName(colName);
+ fld = aTableAlias.cld.getFieldDescriptorByName(anAttrName);
if (fld == null)
{
- ObjectReferenceDescriptor ord =
aTableAlias.cld.getObjectReferenceDescriptorByName(colName);
+ ObjectReferenceDescriptor ord =
aTableAlias.cld.getObjectReferenceDescriptorByName(anAttrName);
if (ord != null)
{
fld = getFldFromReference(aTableAlias, ord);
}
else
{
- fld = getFldFromJoin(aTableAlias, colName);
+ fld = getFldFromJoin(aTableAlias, anAttrName);
}
}
}
@@ -389,7 +402,6 @@
{
break;
}
-
}
}
}
@@ -432,46 +444,79 @@
}
/**
+ * Add the Attribute to the StringBuffer.
+ *
+ * @param attrInfo
+ * @param translate
+ * flag to indicate translation of attrInfo
+ * @param buf
+ * @return true if appended
+ */
+ protected boolean appendAttribute(AttributeInfo attrInfo, boolean
translate, StringBuffer buf)
+ {
+ Iterator iter = attrInfo.iterator();
+
+ while (iter.hasNext())
+ {
+ Object element = iter.next();
+
+ if (element instanceof SingleAttributeInfo)
+ {
+ SingleAttributeInfo sai = (SingleAttributeInfo) element;
+ appendColumn(sai, translate, buf);
+ }
+ else
+ {
+ buf.append(element);
+ }
+ }
+
+ return true;
+ }
+
+ /**
* Append the appropriate ColumnName to the buffer<br>
* if a FIELDDESCRIPTOR is found for the Criteria the colName is taken from
* there otherwise its taken from Criteria. <br>
* field names in functions (ie: sum(name) ) are tried to resolve
* ie: name from FIELDDESCRIPTOR , UPPER(name_test) from Criteria<br>
* also resolve pathExpression adress.city or owner.konti.saldo
+ *
+ * @param anAttribute
+ * @param useOuterJoins
+ * @param aUserAlias
+ * @param buf
+ * @return true if appended
*/
- protected boolean appendColName(String attr, boolean useOuterJoins,
UserAlias aUserAlias, StringBuffer buf)
+ protected boolean appendAttribute(String anAttribute, boolean
useOuterJoins, UserAlias aUserAlias, StringBuffer buf)
{
- AttributeInfo attrInfo = getAttributeInfo(attr, useOuterJoins,
aUserAlias, getQuery().getPathClasses());
- TableAlias tableAlias = attrInfo.tableAlias;
-
- return appendColName(tableAlias, attrInfo.pathInfo, (tableAlias !=
null), buf);
+ AttributeInfo attrInfo = getAttributeInfo(anAttribute, useOuterJoins,
aUserAlias, getQuery().getPathClasses());
+
+ //BRJ: translate must be true to handle expressions ie. "0.9 * (price
* stock)"
+ return appendAttribute(attrInfo, true, buf);
}
/**
- * Append the appropriate ColumnName to the buffer<br>
+ * Append the appropriate aliased ColumnName to the buffer<br>
* if a FIELDDESCRIPTOR is found for the Criteria the colName is taken from
* there otherwise its taken from Criteria. <br>
* field names in functions (ie: sum(name) ) are tried to resolve
* ie: name from FIELDDESCRIPTOR , UPPER(name_test) from Criteria<br>
* also resolve pathExpression adress.city or owner.konti.saldo
+ *
+ * @param anAttribute
+ * @param attrAlias column alias
+ * @param useOuterJoins
+ * @param aUserAlias
+ * @param buf
+ * @return true if appended
*/
- protected boolean appendColName(String attr, String attrAlias, boolean
useOuterJoins, UserAlias aUserAlias,
- StringBuffer buf)
+ protected boolean appendAttribute(String anAttribute, String attrAlias,
boolean useOuterJoins,
+ UserAlias aUserAlias, StringBuffer buf)
{
- AttributeInfo attrInfo = getAttributeInfo(attr, useOuterJoins,
aUserAlias, getQuery().getPathClasses());
- TableAlias tableAlias = attrInfo.tableAlias;
- PathInfo pi = attrInfo.pathInfo;
-
- if (pi.suffix != null)
- {
- pi.suffix = pi.suffix + " as " + attrAlias;
- }
- else
- {
- pi.suffix = " as " + attrAlias;
- }
+ String aliasedAttr = anAttribute + " as " + attrAlias;
- return appendColName(tableAlias, pi, true, buf);
+ return appendAttribute(aliasedAttr, useOuterJoins, aUserAlias, buf);
}
/**
@@ -525,7 +570,7 @@
existingColumns.add(cf.name);
buf.append(",");
- appendColName(cf.name, "ojb_col_" + ojb_col, false, null, buf);
+ appendAttribute(cf.name, "ojb_col_" + ojb_col, false, null,
buf);
ojb_col++;
}
}
@@ -589,7 +634,6 @@
* because we assume you cannot make a relation of the wrong type upon
insertion. Of course,
* you COULD mess the data up manually and this would cause a problem.
*/
-
if (clause != null)
{
stmt.append(clause.toString());
@@ -606,7 +650,6 @@
stmt.append(asSQLStatement(crit));
stmt.append(")");
}
-
}
}
@@ -697,9 +740,9 @@
* @param c BetweenCriteria
* @param buf
*/
- private void appendBetweenCriteria(TableAlias alias, PathInfo pathInfo,
BetweenCriteria c, StringBuffer buf)
+ private void appendBetweenCriteria(AttributeInfo attrInfo, BetweenCriteria
c, StringBuffer buf)
{
- appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
+ appendAttribute(attrInfo, c.isTranslateAttribute(), buf);
buf.append(c.getClause());
appendParameter(c.getValue(), buf);
buf.append(" AND ");
@@ -722,26 +765,25 @@
* Answer the SQL-Clause for a FieldCriteria<br>
* The value of the FieldCriteria will be translated
*
- * @param alias
- * @param pathInfo
+ * @param attrInfo the AttributeInfo
* @param c ColumnCriteria
- * @param buf
+ * @param buf the Buffer to append to
*/
- private void appendFieldCriteria(TableAlias alias, PathInfo pathInfo,
FieldCriteria c, StringBuffer buf)
+ private void appendFieldCriteria(AttributeInfo attrInfo, FieldCriteria c,
StringBuffer buf)
{
- appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
+ appendAttribute(attrInfo, c.isTranslateAttribute(), buf);
buf.append(c.getClause());
if (c.isTranslateField())
{
- appendColName((String) c.getValue(), false,
c.getUserAlias(), buf);
+ appendAttribute((String) c.getValue(), false, c.getUserAlias(),
buf);
}
else
{
buf.append(c.getValue());
}
}
-
+
/**
* Get the column name from the indirection table.
* @param mnAlias
@@ -762,9 +804,9 @@
* @param c InCriteria
* @param buf
*/
- private void appendInCriteria(TableAlias alias, PathInfo pathInfo,
InCriterion c, StringBuffer buf)
+ private void appendInCriteria(AttributeInfo attrInfo, InCriterion c,
StringBuffer buf)
{
- appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
+ appendAttribute(attrInfo, c.isTranslateAttribute(), buf);
buf.append(c.getClause());
if (c.getValue() instanceof Collection)
@@ -798,9 +840,9 @@
* @param c NullCriteria
* @param buf
*/
- private void appendNullCriteria(TableAlias alias, PathInfo pathInfo,
NullCriteria c, StringBuffer buf)
+ private void appendNullCriteria(AttributeInfo attrInfo, NullCriteria c,
StringBuffer buf)
{
- appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
+ appendAttribute(attrInfo, c.isTranslateAttribute(), buf);
buf.append(c.getClause());
}
@@ -819,9 +861,9 @@
* @param c
* @param buf
*/
- private void appendSelectionCriteria(TableAlias alias, PathInfo pathInfo,
SelectionCriteria c, StringBuffer buf)
+ private void appendSelectionCriteria(AttributeInfo attrInfo,
SelectionCriteria c, StringBuffer buf)
{
- appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
+ appendAttribute(attrInfo, c.isTranslateAttribute(), buf);
buf.append(c.getClause());
appendParameter(c.getValue(), buf);
}
@@ -832,9 +874,9 @@
* @param c
* @param buf
*/
- private void appendLikeCriteria(TableAlias alias, PathInfo pathInfo,
LikeCriteria c, StringBuffer buf)
+ private void appendLikeCriteria(AttributeInfo attrInfo, LikeCriteria c,
StringBuffer buf)
{
- appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
+ appendAttribute(attrInfo, c.isTranslateAttribute(), buf);
buf.append(c.getClause());
appendParameter(c.getValue(), buf);
@@ -849,23 +891,23 @@
* @param c SelectionCriteria
* @param buf
*/
- protected void appendCriteria(TableAlias alias, PathInfo pathInfo,
SelectionCriteria c, StringBuffer buf)
+ protected void appendCriteria(AttributeInfo attrInfo, SelectionCriteria c,
StringBuffer buf)
{
if (c instanceof FieldCriteria)
{
- appendFieldCriteria(alias, pathInfo, (FieldCriteria) c, buf);
+ appendFieldCriteria(attrInfo, (FieldCriteria) c, buf);
}
else if (c instanceof NullCriteria)
{
- appendNullCriteria(alias, pathInfo, (NullCriteria) c, buf);
+ appendNullCriteria(attrInfo, (NullCriteria) c, buf);
}
else if (c instanceof BetweenCriteria)
{
- appendBetweenCriteria(alias, pathInfo, (BetweenCriteria) c, buf);
+ appendBetweenCriteria(attrInfo, (BetweenCriteria) c, buf);
}
else if (c instanceof InCriterion)
{
- appendInCriteria(alias, pathInfo, (InCriterion) c, buf);
+ appendInCriteria(attrInfo, (InCriterion) c, buf);
}
else if (c instanceof SqlCriteria)
{
@@ -877,15 +919,28 @@
}
else if (c instanceof LikeCriteria)
{
- appendLikeCriteria(alias, pathInfo, (LikeCriteria) c, buf);
+ appendLikeCriteria(attrInfo, (LikeCriteria) c, buf);
}
else
{
- appendSelectionCriteria(alias, pathInfo, c, buf);
+ appendSelectionCriteria(attrInfo, c, buf);
}
}
/**
+ * Answer the SQL-Clause for a Query
+ * @param q Query
+ */
+ private void appendSQLClause(Query q, SelectionCriteria c, StringBuffer
buf)
+ {
+ buf.append("(");
+ buf.append(getSubQuerySQL(q));
+ buf.append(")");
+ buf.append(c.getClause());
+ appendParameter(c.getValue(), buf);
+ }
+
+ /**
* Answer the SQL-Clause for a SelectionCriteria
* If the Criteria references a class with extents an OR-Clause is
* added for each extent
@@ -903,17 +958,12 @@
// BRJ : criteria attribute is a query
if (c.getAttribute() instanceof Query)
{
- Query q = (Query) c.getAttribute();
- buf.append("(");
- buf.append(getSubQuerySQL(q));
- buf.append(")");
- buf.append(c.getClause());
- appendParameter(c.getValue(), buf);
+ appendSQLClause((Query) c.getAttribute(), c, buf);
return;
}
AttributeInfo attrInfo = getAttributeInfo((String)
c.getAttribute(), false, c.getUserAlias(), c.getPathClasses());
- TableAlias alias = attrInfo.tableAlias;
+ TableAlias alias = attrInfo.getTableAlias();
if (alias != null)
{
@@ -923,28 +973,27 @@
{
// BRJ : surround with braces if alias has extents
buf.append("(");
- appendCriteria(alias, attrInfo.pathInfo, c, buf);
+ appendCriteria(attrInfo, c, buf);
c.setNumberOfExtentsToBind(alias.extents.size());
- Iterator iter = alias.iterateExtents();
- while (iter.hasNext())
+ for (int i = 0;i < alias.extents.size(); i++)
{
- TableAlias tableAlias = (TableAlias) iter.next();
buf.append(" OR ");
- appendCriteria(tableAlias, attrInfo.pathInfo, c, buf);
+ attrInfo.useNextExtent();
+ appendCriteria(attrInfo, c, buf);
}
buf.append(")");
}
else
{
// no extents
- appendCriteria(alias, attrInfo.pathInfo, c, buf);
+ appendCriteria(attrInfo, c, buf);
}
}
else
{
// alias null
- appendCriteria(alias, attrInfo.pathInfo, c, buf);
+ appendCriteria(attrInfo, c, buf);
}
}
@@ -1019,7 +1068,6 @@
Object[] prevKeys;
Object[] keys;
ArrayList descriptors;
- boolean outer = useOuterJoins;
int pathLength;
List hintClasses = null;
String pathAlias = aUserAlias == null ? null :
aUserAlias.getAlias(aPath);
@@ -1057,6 +1105,7 @@
pathLength = descriptors.size();
for (int i = 0; i < pathLength; i++)
{
+ boolean outer = useOuterJoins;
if (!(descriptors.get(i) instanceof
ObjectReferenceDescriptor))
{
// only use Collection- and
ObjectReferenceDescriptor
@@ -1161,7 +1210,7 @@
{
curr = createTableAlias(cld, attrPath,
pathAlias, hintClasses);
- outer = outer || (curr.cld == prev.cld) ||
curr.hasExtents() || useOuterJoins;
+ outer = outer || (curr.cld == prev.cld) ||
curr.hasExtents();
addJoin(prev, prevKeys, curr, keys, outer,
attr);
buildSuperJoinTree(curr, cld, aPath, outer);
@@ -1504,7 +1553,7 @@
}
else
{
- appendColName(cf.name, false, null, buf);
+ appendAttribute(cf.name, false, null, buf);
}
if (!cf.isAscending)
@@ -1536,7 +1585,7 @@
buf.append(",");
}
- appendColName(cf.name, false, null, buf);
+ appendAttribute(cf.name, false, null, buf);
}
}
@@ -1897,10 +1946,127 @@
*/
static final class AttributeInfo
{
- TableAlias tableAlias;
- PathInfo pathInfo;
+ private String m_attribute; // For information only
+ private List m_elements = new ArrayList(); // List of String and
SingleAttributeInfo
+ private int m_extentAliasIndex = 0; // which alias to use
+
+ AttributeInfo(String anAttribute)
+ {
+ m_attribute = anAttribute;
+ }
+
+ /**
+ * Answer the TableAlias of the <b>first</b> SingleAttributeInfo.
+ * @return TableAlias
+ */
+ TableAlias getTableAlias()
+ {
+ TableAlias result = null;
+ Iterator iter = m_elements.iterator();
+ while (iter.hasNext())
+ {
+ Object element = iter.next();
+ if (element instanceof SingleAttributeInfo)
+ {
+ result = ((SingleAttributeInfo) element).m_tableAlias;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Add a SingleAttributeInfo and set it's parent.
+ * @param sai SingleAttributeInfo
+ */
+ void add(SingleAttributeInfo sai)
+ {
+ sai.m_parent = this;
+ m_elements.add(sai);
+ }
+
+ /**
+ * Add a simple String.
+ * @param str
+ */
+ void add(String str)
+ {
+ m_elements.add(str);
+ }
+
+ Iterator iterator()
+ {
+ return m_elements.iterator();
+ }
+
+ String getAttribute()
+ {
+ return m_attribute;
+ }
+
+
+ /**
+ * Increment the extentIndex.
+ */
+ void useNextExtent()
+ {
+ m_extentAliasIndex++;
+ }
+
+ /**
+ * Reset the extentIndex.
+ */
+ void reset()
+ {
+ m_extentAliasIndex = 0;
+ }
}
+
+ /**
+ * Helper Class containing a TableAlias and an Attribute.
+ * ie: A0.emp_firstname
+ */
+ static final class SingleAttributeInfo
+ {
+ private TableAlias m_tableAlias;
+ private String m_attribute;
+ private AttributeInfo m_parent;
+
+ SingleAttributeInfo(TableAlias aTableAlias, String anAttribute)
+ {
+ m_tableAlias = aTableAlias;
+ m_attribute = anAttribute;
+ }
+
+ /**
+ * Answer the TableAlias based on extentAliasIndex of the parent
AttributeInfo.
+ * @return the TableAlias
+ */
+ TableAlias getTableAlias()
+ {
+ TableAlias result = m_tableAlias;
+ int aliasIndex = m_parent.m_extentAliasIndex;
+
+ if (aliasIndex > 0)
+ {
+ result = (TableAlias) m_tableAlias.extents.get(aliasIndex - 1);
+ }
+
+ return result;
+ }
+ String getAttribute()
+ {
+ return m_attribute;
+ }
+
+ AttributeInfo getParent()
+ {
+ return m_parent;
+ }
+ }
+
/**
* This class represents one table (possibly with alias) in the SQL query
*/
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
URL:
http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java?rev=372946&r1=372945&r2=372946&view=diff
==============================================================================
---
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
(original)
+++
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
Fri Jan 27 11:00:27 2006
@@ -258,7 +258,7 @@
{
buf.append(",");
}
- appendColName(columns[i], false, null, buf);
+ appendAttribute(columns[i], false, null, buf);
columnList.add(columns[i]);
}
return columnList;
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/SqlHelper.java
URL:
http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/SqlHelper.java?rev=372946&r1=372945&r2=372946&view=diff
==============================================================================
---
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/SqlHelper.java
(original)
+++
db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/SqlHelper.java
Fri Jan 27 11:00:27 2006
@@ -16,6 +16,7 @@
*/
import java.sql.SQLException;
+import java.util.StringTokenizer;
import org.apache.commons.lang.StringUtils;
import org.apache.ojb.broker.PersistenceBrokerException;
@@ -29,105 +30,68 @@
*/
public class SqlHelper
{
+ /** delimiters to tokenize attributes. */
+ private static final String DELIMITERS = "( ),+-/*";
+
+ /** do not try to reslve these. */
+ private static final String NO_ATTRIBUTES =
"count,min,max,avg,sum,upper,lower,distinct,as";
+
/** define the name of the pseudo column holding the class to be
instantiated. */
public static final String OJB_CLASS_COLUMN = "OJB_CLAZZ";
/**
- * Helper Class for a split column <br>
- * ie: sum (distinct amount) as theAmount
- *
- * <pre>
- * prefix = 'sum (distinct '
- * column = 'amount'
- * suffix = ') as theAmount'
- * </pre>
- */
- public static final class PathInfo
- {
- public String column;
- public String prefix;
- public String suffix;
- public final String path; //original Path
+ * Answer a StringTokenizer for anAttribute.
+ * @param anAttribute the attribute to tokenize
+ * @return StringTokenizer
+ */
+ public static StringTokenizer tokenizeAttribute(String anAttribute)
+ {
- PathInfo(String aPath, String aPrefix, String aColumn, String
aSuffix)
+ return new StringTokenizer(anAttribute, DELIMITERS, true);
+ }
+
+ /**
+ * Answer <em>true</em> if anAttribute is not a token or a 'function'.
+ * @param anAttribute the attribute to check
+ * @return The result of the attribute check.
+ */
+ public static boolean isAttribute(String anAttribute)
+ {
+ // look for delimiters
+ if (DELIMITERS.indexOf(anAttribute) >= 0)
{
- path = aPath;
- column = aColumn;
- prefix = aPrefix;
- suffix = aSuffix;
- }
- }
-
- /**
- * remove functions and () from path <br>
- * ie: avg(amount) -> amount <br>
- * ie: sum (accounts.amount) -> accounts.amount <br>
- * ie: count(distinct id) as theCount-> id <br>
- *
- * @param aPath
- * the path to the attribute
- */
- public static String cleanPath(String aPath)
- {
- return splitPath(aPath).column;
- }
+ return false;
+ }
+ //TODO: should be platform specific !?
+ return NO_ATTRIBUTES.indexOf(anAttribute.toLowerCase()) < 0;
+ }
/**
- * Split a path into column , prefix and suffix, the prefix contains all
- * info up to the column <br>
- * ie: avg(amount) -> amount , avg( , )<br>
- * ie: sum (accounts.amount) as theSum -> accounts.amount , sum( , ) as
- * theSum <br>
- * ie: count( distinct id ) as bla -> id , count(distinct , ) as bla <br>
- * Supports simple expressions ie: price * 1.05
+ * remove functions and () from path <br>
+ * ie: avg(amount) -> amount <br>
+ * ie: sum (accounts.amount) -> accounts.amount <br>
+ * ie: count(distinct id) as theCount-> id <br>
*
- * TODO: cannot resolve multiple attributes in expression
- * ie: price - bonus
- *
- * @param aPath
- * @return PathInfo
+ * @param aPath the path to the attribute
*/
- public static PathInfo splitPath(String aPath)
+ public static String cleanPath(String aPath)
{
- String prefix = null;
- String suffix = null;
- String colName = aPath;
-
- if (aPath == null)
+ StringTokenizer st = new StringTokenizer(aPath, DELIMITERS, false);
+ String result = aPath;
+
+ while (st.hasMoreTokens())
{
- return new PathInfo(null, null, null, null);
+ String token = st.nextToken();
+ if (isAttribute(token))
+ {
+ result = token.trim();
+ break;
+ }
}
- // ignore leading ( and trailing ) ie: sum(avg(col1))
- int braceBegin = aPath.lastIndexOf("(");
- int braceEnd = aPath.indexOf(")");
- int opPos = StringUtils.indexOfAny(aPath, "+-/*");
-
- if (braceBegin >= 0 && braceEnd >= 0 && braceEnd > braceBegin)
- {
- int colBegin;
- int colEnd;
- String betweenBraces;
-
- betweenBraces = aPath.substring(braceBegin + 1, braceEnd).trim();
- // look for ie 'distinct name'
- colBegin = betweenBraces.indexOf(" ");
- // look for multiarg function like to_char(col,'format_mask')
- colEnd = betweenBraces.indexOf(",");
- colEnd = colEnd > 0 ? colEnd : betweenBraces.length();
- prefix = aPath.substring(0, braceBegin + 1) +
betweenBraces.substring(0, colBegin + 1);
- colName = betweenBraces.substring(colBegin + 1, colEnd);
- suffix = betweenBraces.substring(colEnd) +
aPath.substring(braceEnd);
- }
- else if (opPos >= 0)
- {
- colName = aPath.substring(0, opPos).trim();
- suffix = aPath.substring(opPos);
- }
-
- return new PathInfo(aPath, prefix, colName.trim(), suffix);
+ return result;
}
-
+
/**
* Returns the name of the class to be instantiated.
* @param rs the Resultset
Modified:
db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/QueryTest.java
URL:
http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/QueryTest.java?rev=372946&r1=372945&r2=372946&view=diff
==============================================================================
---
db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/QueryTest.java
(original)
+++
db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/QueryTest.java
Fri Jan 27 11:00:27 2006
@@ -1714,7 +1714,7 @@
/**
* ReportQuery with Expression in column need to add table alias to the
field (price)
**/
- public void testReportQueryExpressionInStatement()
+ public void testReportQueryExpressionInStatement1()
{
// TODO: Resolve attributes of expressions
if(ojbSkipKnownIssueProblem("Resolve attributes of expressions"))
return;
@@ -1729,7 +1729,23 @@
assertTrue("Bad query generated. the 'price' field has not table
prefix. SQL Output: " + sql, sql
.equalsIgnoreCase("SELECT A0.Artikel_Nr,A0.Einzelpreis+10 FROM
Artikel A0"));
}
-
+
+ /**
+ * ReportQuery with Expression in column need to add table alias to the
field (price)
+ **/
+ public void testReportQueryExpressionInStatement2()
+ {
+ Criteria crit = new Criteria();
+ ReportQueryByCriteria q = QueryFactory.newReportQuery(Article.class,
crit);
+ q.setAttributes(new String[]{"articleId", "0.9 * (price * stock)"});
+ ClassDescriptor cd = broker.getClassDescriptor(q.getBaseClass());
+ SqlGenerator sqlg = broker.serviceSqlGenerator();
+ String sql = sqlg.getPreparedSelectStatement(q, cd).getStatement();
+
+ assertTrue("Bad query generated. SQL Output: " + sql, sql
+ .equalsIgnoreCase("SELECT A0.Artikel_Nr,0.9 * (A0.Einzelpreis
* A0.Lagerbestand) FROM Artikel A0"));
+ }
+
/**
* Test pathExpression and Extents
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]