User: dsundstrom Date: 02/02/26 15:46:27 Added: src/main/org/jboss/ejb/plugins/cmp/jdbc JDBCEJBQLCompiler.java Log: Compiles EJB-QL and JBossQl, which is a superset of EJB-QL, to SQL. Revision Changes Path 1.1 jboss/src/main/org/jboss/ejb/plugins/cmp/jdbc/JDBCEJBQLCompiler.java Index: JDBCEJBQLCompiler.java =================================================================== /* * JBoss, the OpenSource J2EE webOS * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.ejb.plugins.cmp.jdbc; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.ejb.plugins.cmp.bridge.CMPFieldBridge; import org.jboss.ejb.plugins.cmp.ejbql.ASTAbs; import org.jboss.ejb.plugins.cmp.ejbql.ASTAbstractSchema; import org.jboss.ejb.plugins.cmp.ejbql.ASTAnd; import org.jboss.ejb.plugins.cmp.ejbql.ASTApproximateNumericLiteral; import org.jboss.ejb.plugins.cmp.ejbql.ASTArithmeticComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTArithmeticParenthetical; import org.jboss.ejb.plugins.cmp.ejbql.ASTBetween; import org.jboss.ejb.plugins.cmp.ejbql.ASTBooleanComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTBooleanLiteral; import org.jboss.ejb.plugins.cmp.ejbql.ASTCollectionMemberDeclaration; import org.jboss.ejb.plugins.cmp.ejbql.ASTComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTConcat; import org.jboss.ejb.plugins.cmp.ejbql.ASTConditionalParenthetical; import org.jboss.ejb.plugins.cmp.ejbql.ASTDatetimeComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTEJBQL; import org.jboss.ejb.plugins.cmp.ejbql.ASTEntityComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTExactNumericLiteral; import org.jboss.ejb.plugins.cmp.ejbql.ASTFrom; import org.jboss.ejb.plugins.cmp.ejbql.ASTIdentifier; import org.jboss.ejb.plugins.cmp.ejbql.ASTIn; import org.jboss.ejb.plugins.cmp.ejbql.ASTIsEmpty; import org.jboss.ejb.plugins.cmp.ejbql.ASTLength; import org.jboss.ejb.plugins.cmp.ejbql.ASTLike; import org.jboss.ejb.plugins.cmp.ejbql.ASTLocate; import org.jboss.ejb.plugins.cmp.ejbql.ASTMemberOf; import org.jboss.ejb.plugins.cmp.ejbql.ASTMultDiv; import org.jboss.ejb.plugins.cmp.ejbql.ASTNegation; import org.jboss.ejb.plugins.cmp.ejbql.ASTNot; import org.jboss.ejb.plugins.cmp.ejbql.ASTNullComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTOr; import org.jboss.ejb.plugins.cmp.ejbql.ASTOrderBy; import org.jboss.ejb.plugins.cmp.ejbql.ASTOrderByPath; import org.jboss.ejb.plugins.cmp.ejbql.ASTParameter; import org.jboss.ejb.plugins.cmp.ejbql.ASTPath; import org.jboss.ejb.plugins.cmp.ejbql.ASTPlusMinus; import org.jboss.ejb.plugins.cmp.ejbql.ASTRangeVariableDeclaration; import org.jboss.ejb.plugins.cmp.ejbql.ASTSelect; import org.jboss.ejb.plugins.cmp.ejbql.ASTSqrt; import org.jboss.ejb.plugins.cmp.ejbql.ASTStringComparison; import org.jboss.ejb.plugins.cmp.ejbql.ASTStringLiteral; import org.jboss.ejb.plugins.cmp.ejbql.ASTStringParenthetical; import org.jboss.ejb.plugins.cmp.ejbql.ASTSubstring; import org.jboss.ejb.plugins.cmp.ejbql.ASTWhere; import org.jboss.ejb.plugins.cmp.ejbql.SimpleNode; import org.jboss.ejb.plugins.cmp.ejbql.BasicVisitor; import org.jboss.ejb.plugins.cmp.ejbql.BlockStringBuffer; import org.jboss.ejb.plugins.cmp.ejbql.Catalog; import org.jboss.ejb.plugins.cmp.ejbql.EJBQLParser; import org.jboss.ejb.plugins.cmp.ejbql.JBossQLParser; import org.jboss.ejb.plugins.cmp.ejbql.JBossQLParserVisitor; import org.jboss.ejb.plugins.cmp.ejbql.EJBQLTypes; import org.jboss.ejb.plugins.cmp.ejbql.Node; import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge; import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMPFieldBridge; import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge; import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge; import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData; import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData; import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData; /** * Compiles EJB-QL and JBossQL into SQL. * * @author <a href="mailto:[EMAIL PROTECTED]">Dain Sundstrom</a> * @version $Revision: 1.1 $ */ public class JDBCEJBQLCompiler extends BasicVisitor { // input objects private final Catalog catalog; private Class returnType; private Class[] parameterTypes; private JDBCReadAheadMetaData readAhead; // alias info private String aliasHeaderPrefix; private String aliasHeaderSuffix; private int aliasMaxLength; private int aliasCount; private Map aliases = new HashMap(); private Map relationTableAliases = new HashMap(); // join info private Set declaredPaths = new HashSet(); private Set joinPaths = new HashSet(); private Map leftJoinPaths = new HashMap(); // mapping metadata private JDBCTypeMappingMetaData typeMapping; private JDBCTypeFactory typeFactory; private boolean subquerySupported = false; // output objects private String sql; private Object selectObject; private List inputParameters = new ArrayList(); public JDBCEJBQLCompiler(Catalog catalog) { this.catalog = catalog; } public void compileEJBQL( String ejbql, Class returnType, Class[] parameterTypes, JDBCReadAheadMetaData readAhead) throws Exception { // reset all state variables reset(); // set input arguemts this.returnType = returnType; this.parameterTypes = parameterTypes; this.readAhead = readAhead; // get the parser EJBQLParser parser = new EJBQLParser(new StringReader("")); try { // parse the ejbql into an abstract sytax tree ASTEJBQL ejbqlNode; ejbqlNode = parser.parse(catalog, parameterTypes, ejbql); // translate to sql sql = ejbqlNode.jjtAccept(this, new BlockStringBuffer()).toString(); } catch(Exception e) { // if there is a problem reset the state before exiting reset(); throw e; } catch(Error e) { // lame javacc lexer throws Errors reset(); throw e; } } public void compileJBossQL( String ejbql, Class returnType, Class[] parameterTypes, JDBCReadAheadMetaData readAhead) throws Exception { // reset all state variables reset(); // set input arguemts this.returnType = returnType; this.parameterTypes = parameterTypes; this.readAhead = readAhead; // get the parser JBossQLParser parser = new JBossQLParser(new StringReader("")); try { // parse the ejbql into an abstract sytax tree ASTEJBQL ejbqlNode; ejbqlNode = parser.parse(catalog, parameterTypes, ejbql); // translate to sql sql = ejbqlNode.jjtAccept(this, new BlockStringBuffer()).toString(); } catch(Exception e) { // if there is a problem reset the state before exiting reset(); throw e; } catch(Error e) { // lame javacc lexer throws Errors reset(); throw e; } } private void reset() { returnType = null; parameterTypes = null; readAhead = null; inputParameters = new ArrayList(); aliases = new HashMap(); relationTableAliases = new HashMap(); joinPaths = new HashSet(); leftJoinPaths = new HashMap(); selectObject = null; typeFactory = null; typeMapping = null; aliasHeaderPrefix = null; aliasHeaderSuffix = null; aliasMaxLength = 0; aliasCount = 0; subquerySupported = true; } public String getSQL() { return sql; } public boolean isSelectEntity() { return selectObject instanceof JDBCEntityBridge; } public JDBCEntityBridge getSelectEntity() { return (JDBCEntityBridge)selectObject; } public boolean isSelectField() { return selectObject instanceof JDBCCMPFieldBridge; } public JDBCCMPFieldBridge getSelectField() { return (JDBCCMPFieldBridge)selectObject; } public List getInputParameters() { return inputParameters; } public Object visit(SimpleNode node, Object data) { throw new RuntimeException("Internal error: Found unknown node type in " + "EJB-QL abstract syntax tree: node=" + node); } private void setTypeFactory(JDBCTypeFactory typeFactory) { this.typeFactory = typeFactory; this.typeMapping = typeFactory.getTypeMapping(); aliasHeaderPrefix = typeMapping.getAliasHeaderPrefix(); aliasHeaderSuffix = typeMapping.getAliasHeaderSuffix(); aliasMaxLength = typeMapping.getAliasMaxLength(); subquerySupported = typeMapping.isSubquerySupported(); } private String getAlias(String path) { String alias = (String)aliases.get(path); if(alias == null) { alias = createAlias(path); aliases.put(path, alias); } return alias; } private String createAlias(String path) { StringBuffer alias = new StringBuffer(); alias.append(aliasHeaderPrefix); alias.append(aliasCount++); alias.append(aliasHeaderSuffix); alias.append(path.replace('.', '_')); return alias.substring(0, Math.min(aliasMaxLength, alias.length())); } private String getRelationTableAlias(String path) { String relationTableAlias = (String)relationTableAliases.get(path); if(relationTableAlias == null) { relationTableAlias = createRelationTableAlias(path); relationTableAliases.put(path, relationTableAlias); } return relationTableAlias; } private String createRelationTableAlias(String path) { StringBuffer relationTableAlias = new StringBuffer(); relationTableAlias.append(aliasHeaderPrefix); relationTableAlias.append(aliasCount++); relationTableAlias.append(aliasHeaderSuffix); relationTableAlias.append(path.replace('.', '_')); relationTableAlias.append("_RELATION_TABLE"); return relationTableAlias.substring(0, Math.min(aliasMaxLength, relationTableAlias.length())); } private Class getParameterType(int index) { int zeroBasedIndex = index - 1; Class[] params = parameterTypes; if(zeroBasedIndex < params.length) { return params[zeroBasedIndex]; } return null; } // verify that parameter is the same type as the entity private void verrifyParameterEntityType( int number, JDBCEntityBridge entity) { Class parameterType = getParameterType(number); Class remoteClass = entity.getMetaData().getRemoteClass(); Class localClass = entity.getMetaData().getLocalClass(); if((localClass==null || !localClass.isAssignableFrom(parameterType)) && (remoteClass==null || !remoteClass.isAssignableFrom(parameterType))) { throw new IllegalStateException("Only like types can be " + "compared: from entity=" + entity.getEntityName() + " to parameter type=" + parameterType); } } private void compareEntity( boolean not, Node fromNode, Node toNode, BlockStringBuffer buf) { buf.append("("); if(not) { buf.append("NOT("); } String fromAlias; JDBCEntityBridge fromEntity; ASTPath fromPath = (ASTPath)fromNode; joinPaths.add(fromPath); fromAlias = getAlias(fromPath.getPath()); fromEntity = (JDBCEntityBridge)fromPath.getEntity(); if(toNode instanceof ASTParameter) { ASTParameter toParam = (ASTParameter)toNode; // can only compare like kind entities verrifyParameterEntityType(toParam.number, fromEntity); inputParameters.addAll( QueryParameter.createParameters(toParam.number - 1, fromEntity)); buf.append(SQLUtil.getWhereClause( fromEntity.getPrimaryKeyFields(), fromAlias)); } else { String toAlias; JDBCEntityBridge toEntity; ASTPath toPath = (ASTPath)toNode; joinPaths.add(toPath); toAlias = getAlias(toPath.getPath()); toEntity = (JDBCEntityBridge)toPath.getEntity(); // can only compare like kind entities if(!fromEntity.equals(toEntity)) { throw new IllegalStateException("Only like types can be " + "compared: from entity=" + fromEntity.getEntityName() + " to entity="+toEntity.getEntityName()); } buf.append(SQLUtil.getSelfCompareWhereClause( fromEntity.getPrimaryKeyFields(), fromAlias, toAlias)); } if(not) { buf.append(")"); } buf.append(")"); } public void notExistsClause(ASTPath path, BlockStringBuffer buf) { if(!path.isCMRField()) { throw new IllegalArgumentException("path must be a cmr field"); } JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)path.getCMRField(); JDBCEntityBridge parentEntity = cmrField.getEntity(); String parentAlias = getAlias((String)path.getPath(path.size()-2)); // if exists is not supported we use a left join and is null if(!subquerySupported) { // add the path to the list of paths to left join Set joins = (Set)leftJoinPaths.get(path.getPath(path.size()-2)); if(joins == null) { joins = new HashSet(); leftJoinPaths.put(path.getPath(path.size()-2), joins); } joins.add(path); if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) { JDBCEntityBridge childEntity = (JDBCEntityBridge)cmrField.getRelatedEntity(); String childAlias = getAlias(path.getPath()); buf.append(SQLUtil.getIsNullClause( false, childEntity.getPrimaryKeyFields(), childAlias)); } else { String relationTableAlias = getRelationTableAlias(path.getPath()); buf.append(SQLUtil.getIsNullClause( false, cmrField.getTableKeyFields(), relationTableAlias)); } return; } buf.append("NOT EXISTS ("); if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) { JDBCEntityBridge childEntity = (JDBCEntityBridge)cmrField.getRelatedEntity(); String childAlias = getAlias(path.getPath()); buf.append("SELECT "); buf.append(SQLUtil.getColumnNamesClause( childEntity.getPrimaryKeyFields(), childAlias)); buf.append(" FROM "); buf.append(childEntity.getTableName()).append(" ").append(childAlias); buf.append(" WHERE "); buf.append(SQLUtil.getJoinClause(cmrField, parentAlias, childAlias)); } else { String relationTableAlias = getRelationTableAlias(path.getPath()); buf.append("SELECT "); buf.append(SQLUtil.getColumnNamesClause( cmrField.getTableKeyFields(), relationTableAlias)); buf.append(" FROM "); buf.append(cmrField.getRelationMetaData().getTableName()); buf.append(" "); buf.append(relationTableAlias); buf.append(" WHERE "); buf.append(SQLUtil.getRelationTableJoinClause( cmrField, parentAlias, relationTableAlias)); } buf.append(")"); } public Object visit(ASTEJBQL node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; Node selectNode = node.jjtGetChild(0); Node fromNode = node.jjtGetChild(1); Node whereNode = null; Node orderByNode = null; if(node.jjtGetNumChildren() == 3) { Node temp = node.jjtGetChild(2); if(temp instanceof ASTWhere) { whereNode = temp; } else if(temp instanceof ASTOrderBy) { orderByNode = temp; } } else if(node.jjtGetNumChildren() == 4) { whereNode = node.jjtGetChild(2); orderByNode = node.jjtGetChild(3); } // translate select and add it to the buffer selectNode.jjtAccept(this, buf); // translate where and save results to append later BlockStringBuffer where = new BlockStringBuffer(); if(whereNode != null) { whereNode.jjtAccept(this, where); } // translate order by and save results to append later BlockStringBuffer orderBy = new BlockStringBuffer(); if(orderByNode != null) { orderByNode.jjtAccept(this, orderBy); } // translate from and add it to the buffer buf.append(" "); fromNode.jjtAccept(this, buf); // get theta joins BlockStringBuffer thetaJoin = new BlockStringBuffer(); createThetaJoin(thetaJoin); // add the where clause if(where.length() != 0 && thetaJoin.length() != 0) { buf.append(" ").append(where); buf.append(" AND (").append(thetaJoin).append(")"); } else if(where.length() != 0) { buf.append(" ").append(where); } else if(thetaJoin.length() != 0) { buf.append(" WHERE ").append(thetaJoin); } // add the orderBy clause if(orderBy.length() != 0) { buf.append(" ").append(orderBy); } return buf; } public Object visit(ASTFrom node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; buf.append("FROM "); for(int i=0; i < node.jjtGetNumChildren(); i++) { if(i > 0) { buf.append(", "); } node.jjtGetChild(i).jjtAccept(this, buf); } // add all the additional path tables for(Iterator iter = joinPaths.iterator(); iter.hasNext(); ) { ASTPath path = (ASTPath)iter.next(); for(int i=0; i < path.size(); i++) { declareTables(path, i, buf); } } // get all the left joined paths Set allLeftJoins = new HashSet(); for(Iterator iter = leftJoinPaths.values().iterator(); iter.hasNext(); ) { allLeftJoins.addAll((Set)iter.next()); } // add all parent paths for left joins for(Iterator iter = allLeftJoins.iterator(); iter.hasNext(); ) { ASTPath path = (ASTPath)iter.next(); // don't declare the last one as the first path was left joined for(int i=0; i < path.size()-1; i++) { declareTables(path, i, buf); } } return buf; } private void declareTables(ASTPath path, int i, BlockStringBuffer buf) { if(!path.isCMRField(i) || declaredPaths.contains(path.getPath(i))) { return; } JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)path.getCMRField(i); JDBCEntityBridge entity = (JDBCEntityBridge)path.getEntity(i); buf.append(", "); buf.append(entity.getTableName()); buf.append(" "); buf.append(getAlias(path.getPath(i))); leftJoins(path.getPath(i), buf); if(cmrField.getRelationMetaData().isTableMappingStyle()) { String relationTableAlias = getRelationTableAlias(path.getPath(i)); buf.append(", "); buf.append(cmrField.getRelationMetaData().getTableName()); buf.append(" "); buf.append(relationTableAlias); } declaredPaths.add(path.getPath(i)); } private void leftJoins(String parentPath, BlockStringBuffer buf) { Set paths = (Set)leftJoinPaths.get(parentPath); if(subquerySupported || paths == null) { return; } for(Iterator iter = paths.iterator(); iter.hasNext(); ) { ASTPath path = (ASTPath)iter.next(); JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)path.getCMRField(); JDBCEntityBridge parentEntity = cmrField.getEntity(); String parentAlias = getAlias(parentPath); if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) { JDBCEntityBridge childEntity = (JDBCEntityBridge)cmrField.getRelatedEntity(); String childAlias = getAlias(path.getPath()); buf.append(" LEFT JOIN "); buf.append(childEntity.getTableName()); buf.append(" "); buf.append(childAlias); buf.append(" ON "); buf.append(SQLUtil.getJoinClause( cmrField, parentAlias, childAlias)); } else { String relationTableAlias = getRelationTableAlias(path.getPath()); buf.append(" LEFT JOIN "); buf.append(cmrField.getRelationMetaData().getTableName()); buf.append(" "); buf.append(relationTableAlias); buf.append(" ON "); buf.append(SQLUtil.getRelationTableJoinClause( cmrField, parentAlias, relationTableAlias)); } } } private void createThetaJoin(BlockStringBuffer buf) { Set joinedPaths = new HashSet(); // add all the additional path tables for(Iterator iter = joinPaths.iterator(); iter.hasNext(); ) { ASTPath path = (ASTPath)iter.next(); for(int i=0; i < path.size(); i++) { createThetaJoin(path, i, joinedPaths, buf); } } // get all the left joined paths Set allLeftJoins = new HashSet(); for(Iterator iter = leftJoinPaths.values().iterator(); iter.hasNext(); ) { allLeftJoins.addAll((Set)iter.next()); } // add all parent paths for left joins for(Iterator iter = allLeftJoins.iterator(); iter.hasNext(); ) { ASTPath path = (ASTPath)iter.next(); // don't declare the last one as the first path was left joined for(int i=0; i < path.size()-1; i++) { createThetaJoin(path, i, joinedPaths, buf); } } } private void createThetaJoin( ASTPath path, int i, Set joinedPaths, BlockStringBuffer buf) { if(!path.isCMRField(i) || joinedPaths.contains(path.getPath(i))) { return; } JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)path.getCMRField(i); String childAlias = getAlias(path.getPath(i)); String parentAlias = getAlias(path.getPath(i-1)); if(joinedPaths.size() > 0) { buf.append(" AND "); } if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) { buf.append(SQLUtil.getJoinClause( cmrField, parentAlias, childAlias)); } else { String relationTableAlias = getRelationTableAlias(path.getPath(i)); // parent to relation table buf.append(SQLUtil.getRelationTableJoinClause( cmrField, parentAlias, relationTableAlias)); buf.append(" AND "); // child to relation table buf.append(SQLUtil.getRelationTableJoinClause( cmrField.getRelatedCMRField(), childAlias, relationTableAlias)); } joinedPaths.add(path.getPath(i)); } public Object visit(ASTCollectionMemberDeclaration node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; // first arg is a collection valued path ASTPath path = (ASTPath)node.jjtGetChild(0); // add this path to the list of declared paths declaredPaths.add(path.getPath()); // add this path to the list of join paths so parent paths will be joined joinPaths.add(path); // get the entity at the end of this path JDBCEntityBridge entity = (JDBCEntityBridge)path.getEntity(); // second arg is the identifier ASTIdentifier id = (ASTIdentifier)node.jjtGetChild(1); // get the alias String alias = getAlias(id.identifier); // declare the alias mapping aliases.put(path.getPath(), alias); buf.append(entity.getTableName()); buf.append(" "); buf.append(alias); leftJoins(path.getPath(), buf); return buf; } public Object visit(ASTRangeVariableDeclaration node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; ASTAbstractSchema schema = (ASTAbstractSchema)node.jjtGetChild(0); JDBCEntityBridge entity = (JDBCEntityBridge)schema.entity; ASTIdentifier id = (ASTIdentifier)node.jjtGetChild(1); buf.append(entity.getTableName()); buf.append(" "); buf.append(getAlias(id.identifier)); leftJoins(id.identifier, buf); return buf; } public Object visit(ASTSelect node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; buf.append("SELECT "); if(node.distinct || returnType.equals(Set.class)) { buf.append("DISTINCT "); } ASTPath path = (ASTPath)node.jjtGetChild(0); if(path.isCMPField()) { // set the select object JDBCCMPFieldBridge selectField = (JDBCCMPFieldBridge)path.getCMPField(); setTypeFactory(selectField.getManager().getJDBCTypeFactory()); selectObject = selectField; path.jjtAccept(this, buf); } else { JDBCEntityBridge selectEntity = (JDBCEntityBridge)path.getEntity(); // set the select object setTypeFactory(selectEntity.getManager().getJDBCTypeFactory()); selectObject = selectEntity; joinPaths.add(path); String alias = getAlias(path.getPath()); // get a list of all fields to be loaded List loadFields = new ArrayList(); loadFields.addAll(selectEntity.getPrimaryKeyFields()); if(readAhead.isOnFind()) { String eagerLoadGroupName = readAhead.getEagerLoadGroup(); loadFields.addAll(selectEntity.getLoadGroup(eagerLoadGroupName)); } // get the identifier for this field buf.append(SQLUtil.getColumnNamesClause(loadFields, alias)); } return buf; } public Object visit(ASTNullComparison node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; ASTPath path = (ASTPath)node.jjtGetChild(0); if(path.isCMRField()) { JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)path.getCMRField(); if(cmrField.getRelationMetaData().isTableMappingStyle()) { notExistsClause(path, buf); return buf; } } String alias = getAlias((String)path.getPath(path.size()-2)); JDBCFieldBridge field = (JDBCFieldBridge)path.getField(); buf.append(SQLUtil.getIsNullClause(node.not, field, alias)); return buf; } public Object visit(ASTIsEmpty node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; ASTPath path = (ASTPath)node.jjtGetChild(0); // IS NOT EMPTY is handled automatically by the from clause if(node.not) { joinPaths.add(path); buf.append("TRUE"); } else { notExistsClause(path, buf); } return buf; } /** Compare entity */ public Object visit(ASTMemberOf node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; // regular (not NOT) member of is just a simple entity compare if(!node.not) { // send the args backwards because compre expects that if a // parameter is present it is the second argument. compareEntity( false, node.jjtGetChild(1), node.jjtGetChild(0), buf); return buf; } // setup compare to vars first, so we can compre types in from vars ASTPath toPath = (ASTPath)node.jjtGetChild(1); JDBCCMRFieldBridge toCMRField = (JDBCCMRFieldBridge)toPath.getCMRField(); JDBCEntityBridge toParentEntity = (JDBCEntityBridge)toPath.getEntity(toPath.size()-2); JDBCEntityBridge toChildEntity = (JDBCEntityBridge)toPath.getEntity(); String toParentAlias = getAlias((String)toPath.getPath(toPath.size()-2)); String toChildAlias = getAlias(toPath.getPath()); String relationTableAlias = null; if(toCMRField.getRelationMetaData().isTableMappingStyle()) { relationTableAlias = getRelationTableAlias(toPath.getPath()); } // setup from variables String fromAlias = null; int fromParamNumber = -1; if(node.jjtGetChild(0) instanceof ASTParameter) { ASTParameter fromParam = (ASTParameter)node.jjtGetChild(0); // can only compare like kind entities verrifyParameterEntityType(fromParam.number, toChildEntity); fromParamNumber = fromParam.number; } else { ASTPath fromPath = (ASTPath)node.jjtGetChild(0); JDBCEntityBridge fromEntity = (JDBCEntityBridge)fromPath.getEntity(); fromAlias = getAlias((String)fromPath.getPath()); // can only compare like kind entities if(!fromEntity.equals(toChildEntity)) { throw new IllegalStateException("Only like types can be " + "compared: from entity=" + fromEntity.getEntityName() + " to entity=" + toChildEntity.getEntityName()); } } // add the path to the list of paths to left join Set joins = (Set)leftJoinPaths.get(toPath.getPath(toPath.size()-2)); if(joins == null) { joins = new HashSet(); leftJoinPaths.put(toPath.getPath(toPath.size()-2), joins); } joins.add(toPath); // first part makes toChild not in toParent.child if(!subquerySupported) { // subquery not supported; use a left join and is null buf.append("("); if(relationTableAlias == null) { buf.append(SQLUtil.getIsNullClause( false, toChildEntity.getPrimaryKeyFields(), toChildAlias)); } else { buf.append(SQLUtil.getIsNullClause( false, toCMRField.getTableKeyFields(), relationTableAlias)); } } else { // subquery supported; use not exists buf.append("NOT EXISTS ("); if(relationTableAlias == null) { buf.append("SELECT "); buf.append(SQLUtil.getColumnNamesClause( toChildEntity.getPrimaryKeyFields(), toChildAlias)); buf.append(" FROM "); buf.append(toChildEntity.getTableName()); buf.append(" "); buf.append(toChildAlias); buf.append(" WHERE "); buf.append(SQLUtil.getJoinClause( toCMRField, toParentAlias, toChildAlias)); } else { buf.append("SELECT "); buf.append(SQLUtil.getColumnNamesClause( toCMRField.getRelatedCMRField().getTableKeyFields(), relationTableAlias)); buf.append(" FROM "); buf.append(toCMRField.getRelationMetaData().getTableName()); buf.append(" "); buf.append(relationTableAlias); buf.append(" WHERE "); buf.append(SQLUtil.getRelationTableJoinClause( toCMRField, toParentAlias, relationTableAlias)); } } buf.append(" AND "); // second part makes fromNode equal toChild if(fromAlias != null) { JDBCCMPFieldBridge toChildField; JDBCCMPFieldBridge fromField; // compre pk to pk if(relationTableAlias == null) { buf.append(SQLUtil.getSelfCompareWhereClause( toChildEntity.getPrimaryKeyFields(), toChildAlias, fromAlias)); } else { buf.append(SQLUtil.getRelationTableJoinClause( toCMRField.getRelatedCMRField(), fromAlias, relationTableAlias)); } } else { // add the parameters inputParameters.addAll(QueryParameter.createParameters( fromParamNumber, toChildEntity)); // compare pk to parameter if(relationTableAlias == null) { buf.append(SQLUtil.getWhereClause( toChildEntity.getPrimaryKeyFields(), toChildAlias)); } else { buf.append(SQLUtil.getWhereClause( toCMRField.getRelatedCMRField().getTableKeyFields(), relationTableAlias)); } } buf.append(")"); return buf; } /** compreEntity(arg0, arg1) */ public Object visit(ASTEntityComparison node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; Node arg0 = node.jjtGetChild(0); Node arg1 = node.jjtGetChild(1); if(node.opp == "<>") { compareEntity(true, arg0, arg1, buf); } else { compareEntity(false, arg0, arg1, buf); } return buf; } /** Type-mapping function translation */ public Object visit(ASTConcat node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping("concat"); String[] args = new String[] { node.jjtGetChild(0).jjtAccept( this, new BlockStringBuffer()).toString(), node.jjtGetChild(1).jjtAccept( this, new BlockStringBuffer()).toString(), }; buf.append(function.getFunctionSql(args)); return buf; } /** Type-mapping function translation */ public Object visit(ASTSubstring node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping("substring"); String[] args = new String[] { node.jjtGetChild(0).jjtAccept( this, new BlockStringBuffer()).toString(), node.jjtGetChild(1).jjtAccept( this, new BlockStringBuffer()).toString(), node.jjtGetChild(2).jjtAccept( this, new BlockStringBuffer()).toString() }; buf.append(function.getFunctionSql(args)); return buf; } /** Type-mapping function translation */ public Object visit(ASTLength node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping("length"); String[] args = new String[] { node.jjtGetChild(0).jjtAccept( this, new BlockStringBuffer()).toString() }; buf.append(function.getFunctionSql(args)); return buf; } /** Type-mapping function translation */ public Object visit(ASTLocate node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping("locate"); String[] args = new String[3]; args[0] = node.jjtGetChild(0).jjtAccept( this, new BlockStringBuffer()).toString(); args[1] = node.jjtGetChild(1).jjtAccept( this, new BlockStringBuffer()).toString(); if(node.jjtGetNumChildren()==3) { args[2] = node.jjtGetChild(2).jjtAccept( this, new BlockStringBuffer()).toString(); } else { args[2] = "1"; } buf.append(function.getFunctionSql(args)); return buf; } /** Type-mapping function translation */ public Object visit(ASTAbs node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping("abs"); String[] args = new String[] { node.jjtGetChild(0).jjtAccept( this, new BlockStringBuffer()).toString() }; buf.append(function.getFunctionSql(args)); return buf; } /** Type-mapping function translation */ public Object visit(ASTSqrt node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping("sqrt"); String[] args = new String[] { node.jjtGetChild(0).jjtAccept( this, new BlockStringBuffer()).toString() }; buf.append(function.getFunctionSql(args)); return buf; } /** tableAlias.columnName */ public Object visit(ASTPath node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; if(!node.isCMPField()) { throw new IllegalStateException("Can only visit cmp valued path " + "node. Should have been handled at a higher level."); } // make sure this is mapped to a single column switch(node.type) { case EJBQLTypes.ENTITY_TYPE: case EJBQLTypes.VALUE_CLASS_TYPE: case EJBQLTypes.UNKNOWN_TYPE: throw new IllegalStateException("Can not visit multi-column path " + "node. Should have been handled at a higher level."); } joinPaths.add(node); JDBCCMPFieldBridge cmpField = (JDBCCMPFieldBridge)node.getCMPField(); String alias = getAlias((String)node.getPath(node.size()-2)); buf.append(SQLUtil.getColumnNamesClause(cmpField, alias)); return buf; } public Object visit(ASTAbstractSchema node, Object data) { throw new IllegalStateException("Can not visit abstract schema node. " + "Should have been handled at a higher level."); } /** ? */ public Object visit(ASTParameter node, Object data) { BlockStringBuffer buf = (BlockStringBuffer)data; Class type = getParameterType(node.number); // make sure this is mapped to a single column int ejbqlType = EJBQLTypes.getEJBQLType(type); if(ejbqlType == EJBQLTypes.ENTITY_TYPE || ejbqlType == EJBQLTypes.VALUE_CLASS_TYPE || ejbqlType == EJBQLTypes.UNKNOWN_TYPE) { throw new IllegalStateException("Can not visit multi-column " + "parameter node. Should have been handled at a higher level."); } QueryParameter param = new QueryParameter( node.number - 1, false, // isPrimaryKeyParameter null, // field null, // parameter typeFactory.getJDBCTypeForJavaType(type)); inputParameters.add(param); buf.append("?"); return buf; } }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development