On Jul 28, 2007, at 10:00 AM, Robert Zeigler wrote:
Regarding lines 118 - 125, if attr is null, what should type
default to? I really don't think that will work, honestly.
In my own extended types, I do processing based on the type
attribute... so does the EnumType, for that matter, since it
determines whether to convert to int or string based on the
database type. So, seems like the long-term "right" solution is to
make sure that DbAttribute is something correct...
Sure.
On the long run we may also try to take advantage of JDBC
'java.sql.ParameterMetaData'. When Cayenne project started years ago,
most drivers were fairly low quality, so we have too many workarounds
in the system. At some point we'll need to investigate whether there
is a significant performance penalty with modern drivers when using
PreparedStatememt parameter metadata instead of trying to guess the
types from Cayenne mapping. This should make the translator code
soooo much cleaner.
As for debugging, I put the breakpoint in and started walking back
up the stack.
As predicted, it's QualifierTranslator. More specifically, the
paramsDbType method of QueryAssemblerHelper is returning null.
So, digging a little further, the point at which the paramsDbType
returns null is on the unary operator check.
Lines 286-291 of QueryAssemblerHelper:
protected DbAttribute paramsDbType(Expression e) {
int len = e.getOperandCount();
// ignore unary expressions
if (len < 2) {
return null;
}
e.getOperandCount returns 1.
e is an instance of ASTList, which always returns 1 for the operand
count.
So, you get the null DbAttribute there, which is then passed into
QueryTranslator.appendList, from there into
QueryTranslator.appendLiteral,
In appendLiteral, matchingObject is going to be false for any type
that isn't a data object
(which suggest that /any/ extended type is going to have issues
with inExp... something I will test tomorrow).
I am sure you are right in this assessment. I played with it a bit,
changing the algorithm above to use a parent expression for unary
expressions. This worked, except that I noticed that
ExpressionFactory doesn't initialize parent variable. So I had to fix
that as well. The patch below made against 3.0 (trunk) fixes the
problem for me. Now to be consistent I'll have to fix parent
initialization of all expressions. Let me finish the patch, and apply
it to all branches.
Andrus
Index: src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
===================================================================
--- src/main/java/org/apache/cayenne/exp/parser/ASTIn.java (revision
558748)
+++ src/main/java/org/apache/cayenne/exp/parser/ASTIn.java (working
copy)
@@ -44,6 +44,8 @@
super(ExpressionParserTreeConstants.JJTIN);
jjtAddChild(path, 0);
jjtAddChild(list, 1);
+ path.jjtSetParent(this);
+ list.jjtSetParent(this);
}
protected Object evaluateNode(Object o) throws Exception {
Index: src/main/java/org/apache/cayenne/access/trans/
QueryAssemblerHelper.java
===================================================================
--- src/main/java/org/apache/cayenne/access/trans/
QueryAssemblerHelper.java (revision 558748)
+++ src/main/java/org/apache/cayenne/access/trans/
QueryAssemblerHelper.java (working copy)
@@ -27,6 +27,7 @@
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.SimpleNode;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbJoin;
@@ -285,8 +286,18 @@
*/
protected DbAttribute paramsDbType(Expression e) {
int len = e.getOperandCount();
- // ignore unary expressions
+
+ // for unary expressions, find parent binary - this is a
hack mainly to support
+ // ASTList
if (len < 2) {
+
+ if (e instanceof SimpleNode) {
+ Expression parent = (Expression) ((SimpleNode)
e).jjtGetParent();
+ if (parent != null) {
+ return paramsDbType(parent);
+ }
+ }
+
return null;
}