FileDocCategorySizeDatePackage
SQLQueryParser.javaAPI DocHibernate 3.2.59031Wed Jun 28 08:25:00 BST 2006org.hibernate.loader.custom.sql

SQLQueryParser

public class SQLQueryParser extends Object
author
Gavin King
author
Max Andersen
author
Steve Ebersole

Fields Summary
private final String
originalQueryString
private final ParserContext
context
private final Map
namedParameters
private long
aliasesFound
Constructors Summary
public SQLQueryParser(String queryString, ParserContext context)


	   
		  
		  
		  
		  
		  
		  
		  
	

	     
		this.originalQueryString = queryString;
		this.context = context;
	
Methods Summary
public java.util.MapgetNamedParameters()

		return namedParameters;
	
public java.lang.Stringprocess()

		return substituteParams( substituteBrackets( originalQueryString ) );
	
public booleanqueryHasAliases()

		return aliasesFound>0;
	
private java.lang.StringresolveCollectionProperties(java.lang.String aliasName, java.lang.String propertyName)


		Map fieldResults = context.getPropertyResultsMapByAlias( aliasName );
		SQLLoadableCollection collectionPersister = context.getCollectionPersisterByAlias( aliasName );
		String collectionSuffix = context.getCollectionSuffixByAlias( aliasName );

		if ( "*".equals( propertyName ) ) {
			if( !fieldResults.isEmpty() ) {
				throw new QueryException("Using return-propertys together with * syntax is not supported.");
			}
			
			String selectFragment = collectionPersister.selectFragment( aliasName, collectionSuffix );
			aliasesFound++;
			return selectFragment 
						+ ", " 
						+ resolveProperties( aliasName, propertyName );
		}
		else if ( "element.*".equals( propertyName ) ) {
			return resolveProperties( aliasName, "*" );
		}
		else {
			String[] columnAliases;

			// Let return-propertys override whatever the persister has for aliases.
			columnAliases = ( String[] ) fieldResults.get(propertyName);
			if ( columnAliases==null ) {
				columnAliases = collectionPersister.getCollectionPropertyColumnAliases( propertyName, collectionSuffix );
			}
			
			if ( columnAliases == null || columnAliases.length == 0 ) {
				throw new QueryException(
						"No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
						originalQueryString
				);
			}
			if ( columnAliases.length != 1 ) {
				// TODO: better error message since we actually support composites if names are explicitly listed.
				throw new QueryException(
						"SQL queries only support properties mapped to a single column - property [" +
						propertyName + "] is mapped to " + columnAliases.length + " columns.",
						originalQueryString
				);
			}
			aliasesFound++;
			return columnAliases[0];
		
		}
	
private java.lang.StringresolveProperties(java.lang.String aliasName, java.lang.String propertyName)

		Map fieldResults = context.getPropertyResultsMapByAlias( aliasName );
		SQLLoadable persister = context.getEntityPersisterByAlias( aliasName );
		String suffix = context.getEntitySuffixByAlias( aliasName );

		if ( "*".equals( propertyName ) ) {
			if( !fieldResults.isEmpty() ) {
				throw new QueryException("Using return-propertys together with * syntax is not supported.");
			}			
			aliasesFound++;
			return persister.selectFragment( aliasName, suffix ) ;
		}
		else {

			String[] columnAliases;

			// Let return-propertys override whatever the persister has for aliases.
			columnAliases = (String[]) fieldResults.get( propertyName );
			if ( columnAliases == null ) {
				columnAliases = persister.getSubclassPropertyColumnAliases( propertyName, suffix );
			}

			if ( columnAliases == null || columnAliases.length == 0 ) {
				throw new QueryException(
						"No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
						originalQueryString
				);
			}
			if ( columnAliases.length != 1 ) {
				// TODO: better error message since we actually support composites if names are explicitly listed.
				throw new QueryException(
						"SQL queries only support properties mapped to a single column - property [" + propertyName + "] is mapped to " + columnAliases.length + " columns.",
						originalQueryString
				);
			}			
			aliasesFound++;
			return columnAliases[0];
		}
	
private java.lang.StringsubstituteBrackets(java.lang.String sqlQuery)


		StringBuffer result = new StringBuffer( sqlQuery.length() + 20 );
		int left, right;

		// replace {....} with corresponding column aliases
		for ( int curr = 0; curr < sqlQuery.length(); curr = right + 1 ) {
			if ( ( left = sqlQuery.indexOf( '{", curr ) ) < 0 ) {
				// No additional open braces found in the string, append the
				// rest of the string in its entirty and quit this loop
				result.append( sqlQuery.substring( curr ) );
				break;
			}

			// apend everything up until the next encountered open brace
			result.append( sqlQuery.substring( curr, left ) );

			if ( ( right = sqlQuery.indexOf( '}", left + 1 ) ) < 0 ) {
				throw new QueryException( "Unmatched braces for alias path", sqlQuery );
			}

			String aliasPath = sqlQuery.substring( left + 1, right );
			int firstDot = aliasPath.indexOf( '." );
			if ( firstDot == -1 ) {
				if ( context.isEntityAlias( aliasPath ) ) {
					// it is a simple table alias {foo}
					result.append( aliasPath );
					aliasesFound++;
				} 
				else {
					// passing through anything we do not know : to support jdbc escape sequences HB-898
					result.append( '{" ).append(aliasPath).append( '}" );					
				}
			}
			else {
				String aliasName = aliasPath.substring(0, firstDot);
				boolean isCollection = context.isCollectionAlias( aliasName );
				boolean isEntity = context.isEntityAlias( aliasName );
				
				if ( isCollection ) {
					// The current alias is referencing the collection to be eagerly fetched
					String propertyName = aliasPath.substring( firstDot + 1 );
					result.append( resolveCollectionProperties( aliasName, propertyName ) );
					aliasesFound++;
				} 
				else if ( isEntity ) {
					// it is a property reference {foo.bar}
					String propertyName = aliasPath.substring( firstDot + 1 );
					result.append( resolveProperties( aliasName, propertyName ) );
					aliasesFound++;
				}
				else {
					// passing through anything we do not know : to support jdbc escape sequences HB-898
					result.append( '{" ).append(aliasPath).append( '}" );
				}
	
			}
		}

		// Possibly handle :something parameters for the query ?

		return result.toString();
	
private java.lang.StringsubstituteParams(java.lang.String sqlString)
Substitues JDBC parameter placeholders (?) for all encountered parameter specifications. It also tracks the positions of these parameter specifications within the query string. This accounts for ordinal-params, named-params, and ejb3-positional-params.

param
sqlString The query string.
return
The SQL query with parameter substitution complete.

		ParameterSubstitutionRecognizer recognizer = new ParameterSubstitutionRecognizer();
		ParameterParser.parse( sqlString, recognizer );

		namedParameters.clear();
		namedParameters.putAll( recognizer.namedParameterBindPoints );

		return recognizer.result.toString();