📄 whereparser.java
字号:
//$Id: WhereParser.java 7825 2005-08-10 20:23:55Z oneovthafew $
package org.hibernate.hql.classic;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.engine.JoinSequence;
import org.hibernate.hql.QueryTranslator;
import org.hibernate.persister.collection.CollectionPropertyNames;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.InFragment;
import org.hibernate.type.EntityType;
import org.hibernate.type.LiteralType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper;
/**
* Parses the where clause of a hibernate query and translates it to an
* SQL where clause.
*/
// We should reengineer this class so that, rather than the current ad -
// hoc linear approach to processing a stream of tokens, we instead
// build up a tree of expressions.
// We would probably refactor to have LogicParser (builds a tree of simple
// expressions connected by and, or, not), ExpressionParser (translates
// from OO terms like foo, foo.Bar, foo.Bar.Baz to SQL terms like
// FOOS.ID, FOOS.BAR_ID, etc) and PathExpressionParser (which does much
// the same thing it does now)
public class WhereParser implements Parser {
private final PathExpressionParser pathExpressionParser;
{
pathExpressionParser = new PathExpressionParser();
pathExpressionParser.setUseThetaStyleJoin( true ); //Need this, since join condition can appear inside parens!
}
private static final Set EXPRESSION_TERMINATORS = new HashSet(); //tokens that close a sub expression
private static final Set EXPRESSION_OPENERS = new HashSet(); //tokens that open a sub expression
private static final Set BOOLEAN_OPERATORS = new HashSet(); //tokens that would indicate a sub expression is a boolean expression
private static final Map NEGATIONS = new HashMap();
static {
EXPRESSION_TERMINATORS.add( "and" );
EXPRESSION_TERMINATORS.add( "or" );
EXPRESSION_TERMINATORS.add( ")" );
//expressionTerminators.add(","); // deliberately excluded
EXPRESSION_OPENERS.add( "and" );
EXPRESSION_OPENERS.add( "or" );
EXPRESSION_OPENERS.add( "(" );
//expressionOpeners.add(","); // deliberately excluded
BOOLEAN_OPERATORS.add( "<" );
BOOLEAN_OPERATORS.add( "=" );
BOOLEAN_OPERATORS.add( ">" );
BOOLEAN_OPERATORS.add( "#" );
BOOLEAN_OPERATORS.add( "~" );
BOOLEAN_OPERATORS.add( "like" );
BOOLEAN_OPERATORS.add( "ilike" );
BOOLEAN_OPERATORS.add( "regexp" );
BOOLEAN_OPERATORS.add( "rlike" );
BOOLEAN_OPERATORS.add( "is" );
BOOLEAN_OPERATORS.add( "in" );
BOOLEAN_OPERATORS.add( "any" );
BOOLEAN_OPERATORS.add( "some" );
BOOLEAN_OPERATORS.add( "all" );
BOOLEAN_OPERATORS.add( "exists" );
BOOLEAN_OPERATORS.add( "between" );
BOOLEAN_OPERATORS.add( "<=" );
BOOLEAN_OPERATORS.add( ">=" );
BOOLEAN_OPERATORS.add( "=>" );
BOOLEAN_OPERATORS.add( "=<" );
BOOLEAN_OPERATORS.add( "!=" );
BOOLEAN_OPERATORS.add( "<>" );
BOOLEAN_OPERATORS.add( "!#" );
BOOLEAN_OPERATORS.add( "!~" );
BOOLEAN_OPERATORS.add( "!<" );
BOOLEAN_OPERATORS.add( "!>" );
BOOLEAN_OPERATORS.add( "is not" );
BOOLEAN_OPERATORS.add( "not like" );
BOOLEAN_OPERATORS.add( "not ilike" );
BOOLEAN_OPERATORS.add( "not regexp" );
BOOLEAN_OPERATORS.add( "not rlike" );
BOOLEAN_OPERATORS.add( "not in" );
BOOLEAN_OPERATORS.add( "not between" );
BOOLEAN_OPERATORS.add( "not exists" );
NEGATIONS.put( "and", "or" );
NEGATIONS.put( "or", "and" );
NEGATIONS.put( "<", ">=" );
NEGATIONS.put( "=", "<>" );
NEGATIONS.put( ">", "<=" );
NEGATIONS.put( "#", "!#" );
NEGATIONS.put( "~", "!~" );
NEGATIONS.put( "like", "not like" );
NEGATIONS.put( "ilike", "not ilike" );
NEGATIONS.put( "regexp", "not regexp" );
NEGATIONS.put( "rlike", "not rlike" );
NEGATIONS.put( "is", "is not" );
NEGATIONS.put( "in", "not in" );
NEGATIONS.put( "exists", "not exists" );
NEGATIONS.put( "between", "not between" );
NEGATIONS.put( "<=", ">" );
NEGATIONS.put( ">=", "<" );
NEGATIONS.put( "=>", "<" );
NEGATIONS.put( "=<", ">" );
NEGATIONS.put( "!=", "=" );
NEGATIONS.put( "<>", "=" );
NEGATIONS.put( "!#", "#" );
NEGATIONS.put( "!~", "~" );
NEGATIONS.put( "!<", "<" );
NEGATIONS.put( "!>", ">" );
NEGATIONS.put( "is not", "is" );
NEGATIONS.put( "not like", "like" );
NEGATIONS.put( "not ilike", "ilike" );
NEGATIONS.put( "not regexp", "regexp" );
NEGATIONS.put( "not rlike", "rlike" );
NEGATIONS.put( "not in", "in" );
NEGATIONS.put( "not between", "between" );
NEGATIONS.put( "not exists", "exists" );
}
// Handles things like:
// a and b or c
// a and ( b or c )
// not a and not b
// not ( a and b )
// x between y and z (overloaded "and")
// x in ( a, b, c ) (overloaded brackets)
// not not a
// a is not null (overloaded "not")
// etc......
// and expressions like
// foo = bar (maps to: foo.id = bar.id)
// foo.Bar = 'foo' (maps to: foo.bar = 'foo')
// foo.Bar.Baz = 1.0 (maps to: foo.bar = bar.id and bar.baz = 1.0)
// 1.0 = foo.Bar.Baz (maps to: bar.baz = 1.0 and foo.Bar = bar.id)
// foo.Bar.Baz = a.B.C (maps to: bar.Baz = b.C and foo.Bar = bar.id and a.B = b.id)
// foo.Bar.Baz + a.B.C (maps to: bar.Baz + b.C and foo.Bar = bar.id and a.B = b.id)
// ( foo.Bar.Baz + 1.0 ) < 2.0 (maps to: ( bar.Baz + 1.0 ) < 2.0 and foo.Bar = bar.id)
private boolean betweenSpecialCase = false; //Inside a BETWEEN ... AND ... expression
private boolean negated = false;
private boolean inSubselect = false;
private int bracketsSinceSelect = 0;
private StringBuffer subselect;
private boolean expectingPathContinuation = false;
private int expectingIndex = 0;
// The following variables are stacks that keep information about each subexpression
// in the list of nested subexpressions we are currently processing.
private LinkedList nots = new LinkedList(); //were an odd or even number of NOTs encountered
private LinkedList joins = new LinkedList(); //the join string built up by compound paths inside this expression
private LinkedList booleanTests = new LinkedList(); //a flag indicating if the subexpression is known to be boolean
private String getElementName(PathExpressionParser.CollectionElement element, QueryTranslatorImpl q) throws QueryException {
String name;
if ( element.isOneToMany ) {
name = element.alias;
}
else {
Type type = element.elementType;
if ( type.isEntityType() ) { //ie. a many-to-many
String entityName = ( ( EntityType ) type ).getAssociatedEntityName();
name = pathExpressionParser.continueFromManyToMany( entityName, element.elementColumns, q );
}
else {
throw new QueryException( "illegally dereferenced collection element" );
}
}
return name;
}
public void token(String token, QueryTranslatorImpl q) throws QueryException {
String lcToken = token.toLowerCase();
//Cope with [,]
if ( token.equals( "[" ) && !expectingPathContinuation ) {
expectingPathContinuation = false;
if ( expectingIndex == 0 ) throw new QueryException( "unexpected [" );
return;
}
else if ( token.equals( "]" ) ) {
expectingIndex--;
expectingPathContinuation = true;
return;
}
//Cope with a continued path expression (ie. ].baz)
if ( expectingPathContinuation ) {
boolean pathExpressionContinuesFurther = continuePathExpression( token, q );
if ( pathExpressionContinuesFurther ) return; //NOTE: early return
}
//Cope with a subselect
if ( !inSubselect && ( lcToken.equals( "select" ) || lcToken.equals( "from" ) ) ) {
inSubselect = true;
subselect = new StringBuffer( 20 );
}
if ( inSubselect && token.equals( ")" ) ) {
bracketsSinceSelect--;
if ( bracketsSinceSelect == -1 ) {
QueryTranslatorImpl subq = new QueryTranslatorImpl(
subselect.toString(),
q.getEnabledFilters(),
q.getFactory()
);
try {
subq.compile( q );
}
catch ( MappingException me ) {
throw new QueryException( "MappingException occurred compiling subquery", me );
}
appendToken( q, subq.getSQLString() );
inSubselect = false;
bracketsSinceSelect = 0;
}
}
if ( inSubselect ) {
if ( token.equals( "(" ) ) bracketsSinceSelect++;
subselect.append( token ).append( ' ' );
return;
}
//Cope with special cases of AND, NOT, ()
specialCasesBefore( lcToken );
//Close extra brackets we opened
if ( !betweenSpecialCase && EXPRESSION_TERMINATORS.contains( lcToken ) ) {
closeExpression( q, lcToken );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -