FileDocCategorySizeDatePackage
ParseTree.javaAPI DocGlassfish v2 API21701Tue May 22 16:54:38 BST 2007oracle.toplink.essentials.internal.parsing

ParseTree

public class ParseTree extends Object
INTERNAL

Purpose: A ParseTree contains Node(s). This contains a root Node and provides traversal utilities.

Responsibilities:

  • Add parameters to the query
  • Generate an expression for the query
  • Answer true if the tree has parameters
  • Maintain the primary class name for the query
  • Maintain the root of the parse tree
  • Maintain the context for the parse tree
  • Maintainthe distinct state for the parse tree
  • Print the contents of the parse tree on a string
author
Jon Driscoll and Joel Lucuik
since
TopLink 4.0

Fields Summary
private ParseTreeContext
context
private QueryNode
queryNode
private FromNode
fromNode
private SetNode
setNode
private WhereNode
whereNode
private OrderByNode
orderByNode
private GroupByNode
groupByNode
private HavingNode
havingNode
private ClassLoader
classLoader
private short
distinctState
private boolean
validated
private Set
unusedVariables
Constructors Summary
public ParseTree()
Return a new ParseTree.


             
      
        super();
    
Methods Summary
public voidaddGroupingToQuery(ObjectLevelReadQuery theQuery, GenerationContext generationContext)
INTERNAL Add the grouping to the passed query

        if (hasGroupBy()) {
            ((GroupByNode)getGroupByNode()).addGroupingToQuery(theQuery, generationContext);
        }
    
public voidaddHavingToQuery(ObjectLevelReadQuery theQuery, GenerationContext generationContext)
INTERNAL Add the having to the passed query

        if (hasHaving()) {
            ((HavingNode)getHavingNode()).addHavingToQuery(theQuery, generationContext);
        }
    
public voidaddNonFetchJoinAttributes(ObjectLevelReadQuery theQuery, GenerationContext generationContext)
INTERNAL

        ParseTreeContext context = generationContext.getParseTreeContext();
        for (Iterator i = unusedVariables.iterator(); i.hasNext();) {
            String variable = (String)i.next();
            Expression expr = null;
            if (!context.isRangeVariable(variable)) {
                Node path = context.pathForVariable(variable);
                expr = path.generateExpression(generationContext);
                theQuery.addNonFetchJoinedAttribute(expr);
            } else {
                // unused range variable => not supported yet
                throw EJBQLException.notYetImplemented(context.getQueryInfo(),
                    "Variable [" + variable + "] is defined in a range variable declaration, but not used in the rest of the query.");
            }
        }
    
public voidaddOrderingToQuery(ObjectLevelReadQuery theQuery, GenerationContext generationContext)
INTERNAL Add the ordering to the passed query

        if (hasOrderBy()) {
            ((OrderByNode)getOrderByNode()).addOrderingToQuery(theQuery, generationContext);
        }
    
public voidaddParametersToQuery(DatabaseQuery query)
INTERNAL Add parameters to the query

        //Bug#4646580  Add arguments to query
        if (context.hasParameters()) {
            TypeHelper typeHelper = context.getTypeHelper();
            for (Iterator i = context.getParameterNames().iterator(); i.hasNext();) {
                String param = (String)i.next();
                Object type = context.getParameterType(param);
                Class clazz = typeHelper.getJavaClass(type);
                if (clazz == null) {
                    clazz = Object.class;
                }
                query.addArgument(param, clazz);
            }
        }
    
public voidaddUpdatesToQuery(UpdateAllQuery theQuery, GenerationContext generationContext)
INTERNAL Add the updates to the passed query

        if (getSetNode() != null) {
            ((SetNode)getSetNode()).addUpdatesToQuery(theQuery, generationContext);
        }
    
public voidadjustReferenceClassForQuery(DatabaseQuery theQuery, GenerationContext generationContext)
INTERNAL Adjust the reference class of the passed query if necessary Need to test this for Employee, employee.getAddress(), report query

        Class referenceClass = getReferenceClass(theQuery, generationContext);
        if ((referenceClass != null) && (referenceClass != theQuery.getReferenceClass())) {
            if (theQuery.isObjectLevelReadQuery()) {
                // The referenceClass needs to be changed.
                // This should only happen in an ejbSelect...
                ((ObjectLevelReadQuery)theQuery).setReferenceClass(referenceClass);
                generationContext.setBaseQueryClass(referenceClass);
                ((ObjectLevelReadQuery)theQuery).changeDescriptor(generationContext.getSession());
            } else if (theQuery.isUpdateAllQuery()) {
                ((UpdateAllQuery)theQuery).setReferenceClass(referenceClass);
            } else if (theQuery.isDeleteAllQuery()) {
                ((DeleteAllQuery)theQuery).setReferenceClass(referenceClass);
            }
        }
    
public voidapplyQueryNodeToQuery(DatabaseQuery theQuery, GenerationContext generationContext)
INTERNAL Apply the select or update to the passed query. If there is a single attribute being selected, add it to the query result set If an aggregate is being used, add it to the query result set

        getQueryNode().applyToQuery(theQuery, generationContext);
    
public GenerationContextbuildContext(DatabaseQuery query, oracle.toplink.essentials.internal.sessions.AbstractSession sessionForContext)
INTERNAL Build the context to be used when generating the expression from the parse tree

        if (query.isObjectLevelReadQuery()) {
            return buildContextForReadQuery(sessionForContext);
        } else if (query.isUpdateAllQuery() || query.isDeleteAllQuery()) {
            return new GenerationContext(getContext(), sessionForContext, this);
        }
        return null;
    
public GenerationContextbuildContextForReadQuery(oracle.toplink.essentials.internal.sessions.AbstractSession sessionForContext)
INTERNAL Build the context to be used when generating the expression from the parse tree

        return new SelectGenerationContext(getContext(), sessionForContext, this);
    
public DatabaseQuerycreateDatabaseQuery()
INTERNAL Returns a DatabaseQuery instance for this ParseTree.

        return (queryNode == null) ? null :
            queryNode.createDatabaseQuery(context);
    
public ExpressiongenerateExpression(DatabaseQuery readQuery, GenerationContext generationContext)
INTERNAL Build a context for the expression generation

        Expression selectExpression = getQueryNode().generateExpression(generationContext);
        if (getWhereNode() == null) {
            return selectExpression;
        }
        Expression whereExpression = getWhereNode().generateExpression(generationContext);

        selectExpression = getQueryNode().generateExpression(generationContext);
        if (selectExpression != null) {
            whereExpression = selectExpression.and(whereExpression);
        }
        return whereExpression;
    
private java.lang.ClassgetBaseExpressionClass(Node node, GenerationContext generationContext)

        ParseTreeContext context = generationContext.getParseTreeContext();
        Class clazz = null;
        if (node == null) {
            clazz = null;
        } else if (node.isDotNode()) {
            // DotNode: delegate to left
            clazz = getBaseExpressionClass(node.getLeft(), generationContext);
        } else if (node.isVariableNode()) {
            // VariableNode
            String variable = ((VariableNode)node).getVariableName();
            if (!context.isRangeVariable(variable)) {
                Node path = context.pathForVariable(variable);
                // Variable is defined in JOIN/IN clause => 
                // return the Class from its definition
                clazz = getBaseExpressionClass(path, generationContext);
            } else {
                // Variable is defined in range variable decl =>
                // return its class
                String schema = context.schemaForVariable(variable);
                if (schema != null) {
                    clazz = context.classForSchemaName(schema, generationContext);
                }
            }
        }
        return clazz;
    
public java.lang.ClassLoadergetClassLoader()
INTERNAL Return a class loader

return
java.lang.ClassLoader

        if (classLoader == null) {
            return oracle.toplink.essentials.internal.helper.ConversionManager.getDefaultManager().getLoader();
        } else {
            return classLoader;
        }
    
public ParseTreeContextgetContext()
Return the context for this parse tree

        return context;
    
public shortgetDistinctState()
INTERNAL Return the DISTINCT state for the tree

        return distinctState;
    
public FromNodegetFromNode()
INTERNAL Return the FROM Node

        return fromNode;
    
public GroupByNodegetGroupByNode()
INTERNAL Return the GroupByNode

        return groupByNode;
    
public HavingNodegetHavingNode()
INTERNAL Return the HavingNode

        return havingNode;
    
public OrderByNodegetOrderByNode()
INTERNAL Return the OrderByNode

        return orderByNode;
    
public QueryNodegetQueryNode()
INTERNAL Return the root node for the tree

        return queryNode;
    
public java.lang.ClassgetReferenceClass(DatabaseQuery query, GenerationContext generationContext)
getReferenceClass(): Answer the class which will be the reference class for the query. Resolve this using the node parsed from the "SELECT" of the EJBQL query string

        if (getQueryNode() == null) {
            return null;
        }
        return getQueryNode().getReferenceClass(generationContext);
    
public SetNodegetSetNode()
INTERNAL Return the set node for the tree

        return setNode;
    
public WhereNodegetWhereNode()
INTERNAL Return the Where node

        return whereNode;
    
public booleanhasGroupBy()
INTERNAL Does this EJBQL have a Grouping Clause

        return getGroupByNode() != null;
    
public booleanhasHaving()
INTERNAL Does this EJBQL have a Having Clause

        return getHavingNode() != null;
    
public booleanhasOrderBy()
INTERNAL Does this EJBQL have an Ordering Clause

        return getOrderByNode() != null;
    
public voidinitBaseExpression(ObjectLevelReadQuery theQuery, GenerationContext generationContext)
INTERNAL Initialize the base expression in the generation context.

        String variable = getFromNode().getFirstVariable();
        ParseTreeContext context = generationContext.getParseTreeContext();
        if (context.isRangeVariable(variable)) {
            Class referenceClass = theQuery.getReferenceClass();
            // Create a new expression builder for the reference class
            ExpressionBuilder builder = new ExpressionBuilder(referenceClass);
            // Use the expression builder as the default expression builder for the query
            theQuery.setExpressionBuilder(builder);
            // Add the expression builder to the expression cache in the context
            generationContext.setBaseExpression(variable, builder);
        } else {
            // Get the declaring node for the variable
            Node path = context.pathForVariable(variable);
            // Get the ExpressionBuilder of the range variable for the path
            Class baseClass = getBaseExpressionClass(path, generationContext);
            // Use the base ExpressionBuilder as the default for the query
            theQuery.setExpressionBuilder(new ExpressionBuilder(baseClass));
            // and change the reference class accordingly
            theQuery.setReferenceClass(baseClass);
            theQuery.changeDescriptor(generationContext.getSession());
            generationContext.setBaseQueryClass(baseClass);
            // Set the node expression as base expression
            generationContext.setBaseExpression(
                variable, path.generateExpression(generationContext));
        }
    
public voidinitBaseExpression(ModifyAllQuery theQuery, GenerationContext generationContext)
INTERNAL Initialize the base expression in the generation context.

        ModifyNode queryNode = (ModifyNode)getQueryNode();
        String variable = queryNode.getCanonicalAbstractSchemaIdentifier();
        Class referenceClass = theQuery.getReferenceClass();
        // Create a new expression builder for the reference class
        ExpressionBuilder builder = new ExpressionBuilder(referenceClass);
        // Use the expression builder as the default expression builder for the query
        theQuery.setExpressionBuilder(builder);
        // Add the expression builder to the expression cache in the context
        generationContext.setBaseExpression(variable, builder);        
    
protected voidqualifyAttributeAccess(ParseTreeContext context)
INTERNAL This method handles any unqualified field access in bulk UPDATE and DELETE statements. A UPDATE or DELETE statement may not define an identification variable. In this case any field accessed from the current class is not qualified with an identification variable, e.g. UPDATE Customer SET name = :newname The method goes through the expressions of the SET clause and the WHERE clause of such an DELETE and UPDATE statement and qualifies the field access using the abstract schema name as qualifier.

        if ((queryNode.isUpdateNode() || queryNode.isDeleteNode()) &&
            ((ModifyNode)queryNode).getAbstractSchemaIdentifier() == null) {
            if (setNode != null) {
                setNode.qualifyAttributeAccess(context);
            }
            if (whereNode != null) {
                whereNode.qualifyAttributeAccess(context);
            }
        }
    
public voidsetClassLoader(java.lang.ClassLoader loader)
INTERNAL: Set the class loader for this parse tree

param
loader

        this.classLoader = loader;
    
public voidsetContext(ParseTreeContext newContext)
INTERNAL Set the context for this parse tree

        context = newContext;
    
public voidsetDistinctState(short newDistinctState)
INTERNAL Set the DISTINCT state for the tree

        distinctState = newDistinctState;
    
public voidsetFromNode(FromNode fromNode)
INTERNAL Set the FROM node for the query

        this.fromNode = fromNode;
    
public voidsetGroupByNode(GroupByNode newGroupByNode)
INTERNAL Set the Group by node

        groupByNode = newGroupByNode;
    
public voidsetHavingNode(HavingNode newHavingNode)
INTERNAL Set the Having node

        havingNode = newHavingNode;
    
public voidsetOrderByNode(OrderByNode newOrderByNode)
INTERNAL Set the Order by node

        orderByNode = newOrderByNode;
    
public voidsetQueryNode(QueryNode newQueryNode)
INTERNAL Set the Select node

        queryNode = newQueryNode;
    
public voidsetSelectionCriteriaForQuery(DatabaseQuery theQuery, GenerationContext generationContext)

        theQuery.setSelectionCriteria(generateExpression(theQuery, generationContext));
    
public voidsetSetNode(SetNode newSetNode)
INTERNAL Set the Where node

        setNode = newSetNode;
    
public voidsetWhereNode(WhereNode newWhereNode)
INTERNAL Set the Where node

        whereNode = newWhereNode;
    
public java.lang.StringtoString()
INTERNAL Print the contents of the parse tree on a string

        StringBuffer buffer = new StringBuffer();
        buffer.append(getContext().toString());
        return ToStringLocalization.buildMessage("context", (Object[])null) + " " + buffer.toString();
    
public booleanusesDistinct()
INTERNAL Answer true if DISTINCT has been chosen.

        return distinctState == ObjectLevelReadQuery.USE_DISTINCT;
    
protected voidvalidate(oracle.toplink.essentials.internal.sessions.AbstractSession session, java.lang.ClassLoader classLoader)
INTERNAL Validate the parse tree.

        validate(new TypeHelperImpl(session, classLoader));
    
public voidvalidate(TypeHelper typeHelper)
INTERNAL Validate the parse tree.

        ParseTreeContext context = getContext();
        context.setTypeHelper(typeHelper);
        validate(context);
    
public voidvalidate(ParseTreeContext context)
INTERNAL Validate the parse tree.

        if (validated) {
            // already validated => return
            return;
        }
        
        validated = true;
        context.enterScope();
        if (fromNode != null) {
            fromNode.validate(context);
        }
        queryNode.validate(context);
        qualifyAttributeAccess(context);
        if (setNode != null) {
            setNode.validate(context);
        }
        if (whereNode != null) {
            whereNode.validate(context);
        }
        if (hasOrderBy()) {
            orderByNode.validate(context, (SelectNode)queryNode);
        }
        if (hasGroupBy()) {
            groupByNode.validate(context, (SelectNode)queryNode);
        }
        if (hasHaving()) {
            havingNode.validate(context, groupByNode);
        }
        // store the set od unused variable for later use
        unusedVariables = context.getUnusedVariables();
        context.leaveScope();
    
public voidverifySelect(DatabaseQuery theQuery, GenerationContext generationContext)
INTERNAL Verify that the alias in the SELECT is valid. Invalid: SELECT OBJECT(badAlias) FROM Employee employee.... Valid: SELECT OBJECT(employee) FROM Employee employee....

        if (theQuery.isObjectLevelReadQuery()) {
            //verify the selected alias,
            //this will throw an error if the alias is bad
            ((SelectNode)getQueryNode()).verifySelectedAlias(generationContext);
        }