From: Paul H. <pha...@us...> - 2005-03-01 16:25:35
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5548/nhibernate/src/NHibernate/Hql Modified Files: FilterTranslator.cs FromParser.cs FromPathExpressionParser.cs OrderByParser.cs PathExpressionParser.cs QueryTranslator.cs SelectParser.cs SelectPathExpressionParser.cs WhereParser.cs Log Message: Various refactorings on the way to 2.1 querying capability Index: PathExpressionParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/PathExpressionParser.cs,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** PathExpressionParser.cs 17 Jan 2005 03:40:56 -0000 1.20 --- PathExpressionParser.cs 1 Mar 2005 16:24:46 -0000 1.21 *************** *** 45,77 **** private int dotcount; ! ! /// <summary></summary> ! protected string currentName; ! ! /// <summary></summary> ! protected string currentProperty; ! ! /// <summary></summary> ! protected QueryJoinFragment join; ! ! /// <summary></summary> ! protected string[ ] columns; ! ! /// <summary></summary> ! protected string[ ] collectionElementColumns; ! ! private string collectionName; //protected private string collectionOwnerName; private string collectionRole; ! private string collectionTable; ! ! /// <summary></summary> ! protected IType collectionElementType; ! private string componentPath; - /// <summary></summary> ! protected IType type; ! private string path; private bool ignoreInitialJoin; --- 45,60 ---- private int dotcount; ! private string currentName; ! private string currentProperty; ! private string oneToOneOwnerName; ! private QueryJoinFragment join; ! private string[ ] columns; ! private string collectionName; private string collectionOwnerName; private string collectionRole; ! //private StringBuilder componentPath = new StringBuilder(); private string componentPath; /// <summary></summary> ! private IType type; private string path; private bool ignoreInitialJoin; *************** *** 79,82 **** --- 62,66 ---- private JoinType joinType = JoinType.InnerJoin; //default mode private bool useThetaStyleJoin = true; + private IPropertyMapping currentPropertyMapping; /// <summary></summary> *************** *** 94,100 **** } ! private void AddJoin( string table, string name, string[ ] rhsCols, QueryTranslator q ) { ! string[ ] lhsCols = CurrentColumns( q ); join.AddJoin( table, name, lhsCols, rhsCols, joinType ); } --- 78,89 ---- } ! private IPropertyMapping PropertyMapping { ! get { return currentPropertyMapping; } ! } ! ! private void AddJoin( string table, string name, string[] rhsCols ) ! { ! string[] lhsCols = CurrentColumns( ); join.AddJoin( table, name, lhsCols, rhsCols, joinType ); } *************** *** 113,118 **** currentName = q.CreateNameFor( clazz ); q.AddType( currentName, clazz ); ! ILoadable p = q.GetPersister( clazz ); ! join.AddJoin( p.TableName, currentName, joinColumns, p.IdentifierColumnNames, joinType ); return currentName; } --- 102,108 ---- currentName = q.CreateNameFor( clazz ); q.AddType( currentName, clazz ); ! IQueryable classPersister = q.GetPersister( clazz ); ! join.AddJoin( classPersister.TableName, currentName, joinColumns, classPersister.IdentifierColumnNames, joinType ); ! currentPropertyMapping = classPersister; return currentName; } *************** *** 141,144 **** --- 131,135 ---- Reset( q ); //reset the dotcount (but not the path) currentName = alias; //after reset! + currentPropertyMapping = q.GetPropertyMapping( currentName ); if( !ignoreInitialJoin ) { *************** *** 165,168 **** --- 156,160 ---- } currentName = token; + currentPropertyMapping = q.GetPropertyMapping( currentName ); } } *************** *** 175,180 **** else if( collectionName != null ) { ! CollectionPersister p = q.GetCollectionPersister( collectionRole ); ! DoCollectionProperty( token, p, collectionName ); continuation = false; } --- 167,172 ---- else if( collectionName != null ) { ! //IQueryableCollection p = q.GetCollectionPersister( collectionRole ); ! //DoCollectionProperty( token, p, collectionName ); continuation = false; } *************** *** 188,192 **** // Do the corresponding RHS ! IType propertyType = GetPropertyType( q ); if( propertyType == null ) --- 180,184 ---- // Do the corresponding RHS ! IType propertyType = PropertyType; if( propertyType == null ) *************** *** 195,279 **** } ! if( propertyType.IsComponentType || propertyType.IsObjectType ) { ! if( componentPath == null ) ! { ! componentPath = token; ! } ! else ! { ! if( token != null ) ! { ! componentPath += StringHelper.Dot + token; ! } ! } } ! else { ! if( propertyType.IsEntityType ) ! { ! System.Type memberClass = ( ( EntityType ) propertyType ).PersistentClass; ! IQueryable memberPersister = q.GetPersister( memberClass ); ! if( ! // if its "id" ! EntityID.Equals( token ) || ( ! //or its the id property name ! memberPersister.HasIdentifierProperty && ! memberPersister.IdentifierPropertyName.Equals( token ) ) ) ! { ! // special shortcut for id properties, skip the join! ! // this must only occur at the _end_ of a path expression ! if( componentPath == null ) ! { ! componentPath = "id"; ! } ! else ! { ! componentPath += ".id"; ! } ! } ! else ! { ! string name = q.CreateNameFor( memberClass ); ! q.AddType( name, memberClass ); ! string[ ] keyColNames = memberPersister.IdentifierColumnNames; ! AddJoin( memberPersister.TableName, name, keyColNames, q ); ! currentName = name; ! currentProperty = token; ! q.AddPathAliasAndJoin( path.Substring( 0, ( path.LastIndexOf( StringHelper.Dot ) ) - ( 0 ) ), name, join ); ! componentPath = null; ! } ! } ! else if( propertyType.IsPersistentCollectionType ) ! { ! collectionRole = ( ( PersistentCollectionType ) propertyType ).Role; ! CollectionPersister collPersister = q.GetCollectionPersister( collectionRole ); ! string[ ] colNames = collPersister.KeyColumnNames; ! ! string name = q.CreateNameForCollection( collectionRole ); ! string tableName = collPersister.QualifiedTableName; ! AddJoin( tableName, name, colNames, q ); ! if( collPersister.HasWhere ) ! { ! join.AddCondition( collPersister.GetSQLWhereString( name ) ); ! } ! DoCollectionProperty( token, collPersister, name ); ! collectionName = name; ! collectionOwnerName = currentName; ! collectionTable = collPersister.QualifiedTableName; ! currentName = null; ! currentProperty = null; ! componentPath = null; ! } ! else ! { ! if( token != null ) ! { ! throw new QueryException( "dereferenced: " + currentProperty ); ! } ! } } } } } --- 187,308 ---- } ! if( propertyType.IsComponentType ) { ! DereferenceComponent( token ); } ! else if( propertyType.IsEntityType ) { ! DereferenceEntity( token, (EntityType) propertyType, q ); } + else if( propertyType.IsPersistentCollectionType ) + { + DereferenceCollection( token, ( (PersistentCollectionType) propertyType).Role, q ); + } + else if( token != null ) + { + throw new QueryException( "dereferenced: " + currentProperty ); + } + } + } + } + + /// <summary> + /// + /// </summary> + /// <param name="propertyName"></param> + /// <param name="propertyType"></param> + /// <param name="q"></param> + /// <remarks>NOTE: we avoid joining to the next table if the named property is just the foreign key value</remarks> + private void DereferenceEntity( string propertyName, EntityType propertyType, QueryTranslator q ) + { + //if its "id" + bool isIdShortcut = EntityID.Equals(propertyName) && !propertyType.IsUniqueKeyReference; + + //or its the id property name + string idPropertyName; + try + { + idPropertyName = propertyType.GetIdentifierOrUniqueKeyPropertyName( q.GetFactory() ); + } + catch (MappingException me) + { + throw new QueryException(me); + } + bool isNamedIdPropertyShortcut = idPropertyName != null && idPropertyName.Equals( propertyName ); + + if ( isIdShortcut || isNamedIdPropertyShortcut ) + { + // special shortcut for id properties, skip the join! + // this must only occur at the _end_ of a path expression + DereferenceProperty( propertyName ); + } + else + { + System.Type entityClass = propertyType.AssociatedClass; + String name = q.CreateNameFor( entityClass ); + q.AddType( name, entityClass ); + IQueryable memberPersister = q.GetPersister( entityClass ); + //String[] keyColNames = memberPersister.getIdentifierColumnNames(); + string[] keyColNames; + try + { + keyColNames = propertyType.GetReferencedColumns( q.GetFactory() ); + } + catch (MappingException me) + { + throw new QueryException(me); + } + AddJoin( memberPersister.TableName, name, keyColNames ); + if ( propertyType.IsOneToOne ) + { + oneToOneOwnerName = currentName; + } + currentName = name; + currentProperty = propertyName; + q.AddPathAliasAndJoin( path.Substring( 0, path.LastIndexOf( StringHelper.Dot ) ), name, join ); + componentPath = null; + //componentPath = new StringBuilder( ); + currentPropertyMapping = memberPersister; + } + } + + private void DereferenceProperty( string propertyName ) + { + if ( propertyName != null ) + { + if ( componentPath != null && componentPath.Length > 0 ) + { + componentPath += StringHelper.Dot; + //componentPath.Append( StringHelper.Dot ); } + componentPath += propertyName; + //componentPath.Append( propertyName ); + } + } + + private void DereferenceComponent( string propertyName ) + { + DereferenceProperty( propertyName ); + } + + private void DereferenceCollection(String propertyName, String role, QueryTranslator q) + { + collectionRole = role; + IQueryableCollection collPersister = q.GetCollectionPersister( role ); + string[] colNames = collPersister.KeyColumnNames; + string name = q.CreateNameForCollection(role); + AddJoin( collPersister.TableName, name, colNames ); + + if ( collPersister.HasWhere ) + { + join.AddCondition( collPersister.GetSQLWhereString( name ) ); } + collectionName = name; + collectionOwnerName = currentName; + currentName = name; + currentProperty = propertyName; + componentPath = null; + //componentPath = new StringBuilder(); + currentPropertyMapping = new CollectionPropertyMapping( collPersister ); } *************** *** 286,293 **** return EntityID; } else { ! return currentProperty + ! ( ( componentPath == null ) ? String.Empty : StringHelper.Dot + componentPath ); } } --- 315,325 ---- return EntityID; } + else if ( componentPath != null && componentPath.Length > 0 ) + { + return currentProperty + StringHelper.Dot + componentPath; + } else { ! return currentProperty; } } *************** *** 298,307 **** if( currentProperty == null ) { ! IClassPersister p = q.GetPersisterForName( currentName ); ! type = NHibernateUtil.Entity( p.MappedClass ); } else { ! type = GetPropertyType( q ); } } --- 330,338 ---- if( currentProperty == null ) { ! type = PropertyMapping.Type; } else { ! type = PropertyType; } } *************** *** 310,326 **** /// /// </summary> - /// <param name="q"></param> /// <returns></returns> ! protected IType GetPropertyType( QueryTranslator q ) { ! string path = PropertyPath; ! IType type = q.GetPersisterForName( currentName ).GetPropertyType( path ); ! ! if( type == null ) { ! throw new QueryException( "could not resolve property type: " + path ); ! } ! return type; } --- 341,359 ---- /// /// </summary> /// <returns></returns> ! protected IType PropertyType { ! get { ! string path = PropertyPath; ! IType type = PropertyMapping.ToType( PropertyPath ); ! if( type == null ) ! { ! throw new QueryException( "could not resolve property type: " + path ); ! } ! ! return type; ! } } *************** *** 328,342 **** /// /// </summary> - /// <param name="q"></param> /// <returns></returns> ! protected string[ ] CurrentColumns( QueryTranslator q ) { string path = PropertyPath; ! string[ ] columns = q.GetPersisterForName( currentName ).ToColumns( currentName, path ); ! if( columns == null ) { throw new QueryException( "could not resolve property columns: " + path ); } ! return columns; } --- 361,374 ---- /// /// </summary> /// <returns></returns> ! protected string[ ] CurrentColumns( ) { string path = PropertyPath; ! string[ ] propertyColumns = PropertyMapping.ToColumns( currentName, path ); ! if( propertyColumns == null ) { throw new QueryException( "could not resolve property columns: " + path ); } ! return propertyColumns; } *************** *** 349,355 **** collectionName = null; collectionRole = null; - collectionTable = null; - collectionElementColumns = null; - collectionElementType = null; componentPath = null; type = null; --- 381,384 ---- *************** *** 358,361 **** --- 387,391 ---- expectingCollectionIndex = false; continuation = false; + currentPropertyMapping = null; } *************** *** 369,373 **** { Reset( q ); ! path = String.Empty; } } --- 399,403 ---- { Reset( q ); ! path = null; } } *************** *** 380,458 **** { ignoreInitialJoin = false; ! if( IsCollectionValued ) { ! columns = collectionElementColumns; ! type = collectionElementType; } else { ! if( !continuation ) ! { ! IType propertyType = GetPropertyType( q ); ! if( propertyType != null && propertyType.IsPersistentCollectionType ) ! { ! collectionRole = ( ( PersistentCollectionType ) propertyType ).Role; ! collectionName = q.CreateNameForCollection( collectionRole ); ! } ! } ! if( collectionRole != null ) ! { ! //special case; expecting: [index] ! CollectionPersister memberPersister = q.GetCollectionPersister( collectionRole ); ! ! if( !memberPersister.HasIndex ) ! { ! throw new QueryException( "unindexed collection before []" ); ! } ! string[ ] indexCols = memberPersister.IndexColumnNames; ! if( indexCols.Length != 1 ) ! { ! throw new QueryException( "composite-index appears in []: " + path ); ! } ! string[ ] keyCols = memberPersister.KeyColumnNames; ! ! JoinFragment ojf = q.CreateJoinFragment( useThetaStyleJoin ); ! ojf.AddCrossJoin( memberPersister.QualifiedTableName, collectionName ); ! if( memberPersister.IsOneToMany ) ! { ! IQueryable persister = q.GetPersister( ( ( EntityType ) memberPersister.ElementType ).PersistentClass ); ! ojf.AddJoins( ! persister.FromJoinFragment( collectionName, true, false ), ! persister.WhereJoinFragment( collectionName, true, false ) ! ); ! } ! if( !continuation ) ! { ! AddJoin( memberPersister.QualifiedTableName, collectionName, keyCols, q ); ! } ! join.AddCondition( collectionName, indexCols, " = " ); ! string[ ] eltCols = memberPersister.ElementColumnNames; ! //if ( eltCols.Length!=1 ) throw new QueryException("composite-id collection element []"); ! CollectionElement elem = new CollectionElement(); ! elem.ElementColumns = StringHelper.Prefix( eltCols, collectionName + StringHelper.Dot ); ! elem.Type = memberPersister.ElementType; ! elem.IsOneToMany = memberPersister.IsOneToMany; ! elem.Alias = collectionName; ! elem.Join = join; ! collectionElements.Add( elem ); //addlast ! SetExpectingCollectionIndex(); ! q.AddCollection( collectionName, collectionRole ); ! q.AddJoin( collectionName, ojf ); ! } ! else ! { ! columns = CurrentColumns( q ); ! SetType( q ); ! } } ! //important!! ! continuation = false; } --- 410,477 ---- { ignoreInitialJoin = false; ! ! IType propertyType = PropertyType; ! if( propertyType != null && propertyType.IsPersistentCollectionType ) { ! collectionRole = ( ( PersistentCollectionType ) propertyType ).Role; ! collectionName = q.CreateNameForCollection( collectionRole ); ! PrepareForIndex( q ); } else { ! columns = CurrentColumns( ); ! SetType( q ); ! } ! //important!! ! continuation = false; ! } ! private void PrepareForIndex( QueryTranslator q ) ! { ! IQueryableCollection collPersister = q.GetCollectionPersister( collectionRole ); ! if( !collPersister.HasIndex ) ! { ! throw new QueryException( "unindexed collection before []" ); ! } ! string[ ] indexCols = collPersister.IndexColumnNames; ! if( indexCols.Length != 1 ) ! { ! throw new QueryException( "composite-index appears in []: " + path ); ! } ! string[ ] keyCols = collPersister.KeyColumnNames; ! JoinFragment ojf = q.CreateJoinFragment( useThetaStyleJoin ); ! ojf.AddCrossJoin( collPersister.TableName, collectionName ); ! ojf.AddFromFragmentString( join.ToFromFragmentString ); ! if( collPersister.IsOneToMany ) ! { ! IQueryable persister = (IQueryable) collPersister.ElementPersister; ! ojf.AddJoins( ! ( (IJoinable) persister).FromJoinFragment( collectionName, true, false ), ! ( (IJoinable) persister).WhereJoinFragment( collectionName, true, false ) ! ); ! } + if( !continuation ) + { + AddJoin( collPersister.TableName, collectionName, keyCols ); } + join.AddCondition( collectionName, indexCols, " = " ); ! string[ ] eltCols = collPersister.ElementColumnNames; ! ! CollectionElement elem = new CollectionElement(); ! elem.ElementColumns = StringHelper.Qualify( collectionName, eltCols ); ! elem.Type = collPersister.ElementType; ! elem.IsOneToMany = collPersister.IsOneToMany; ! elem.Alias = collectionName; ! elem.Join = join; ! collectionElements.Add( elem ); //addlast ! SetExpectingCollectionIndex(); + q.AddCollection( collectionName, collectionRole ); + q.AddJoin( collectionName, ojf ); } *************** *** 554,558 **** //TODO: refactor to .sql package return new StringBuilder( "SELECT " ) ! .Append( String.Join( ", ", collectionElementColumns ) ) .Append( " FROM " ) /*.Append(collectionTable) --- 573,577 ---- //TODO: refactor to .sql package return new StringBuilder( "SELECT " ) ! .Append( String.Join( ", ", CurrentColumns() ) ) .Append( " FROM " ) /*.Append(collectionTable) *************** *** 568,574 **** public bool IsCollectionValued { ! get { return collectionElementColumns != null; } } /// <summary> /// --- 587,595 ---- public bool IsCollectionValued { ! // TODO: Is there a better way ! get { return collectionName != null && !PropertyType.IsPersistentCollectionType; } } + /// <summary> /// *************** *** 587,592 **** public string AddFromAssociation( QueryTranslator q ) { ! q.AddFrom( currentName, join ); ! return currentName; } --- 608,620 ---- public string AddFromAssociation( QueryTranslator q ) { ! if ( IsCollectionValued ) ! { ! return AddFromCollection( q ); ! } ! else ! { ! q.AddFrom( currentName, join ); ! return currentName; ! } } *************** *** 598,633 **** public string AddFromCollection( QueryTranslator q ) { if( collectionElementType == null ) { ! throw new QueryException( ! "must specify 'elements' for collection valued property in from clause: " + path ! ); } ! if( !collectionElementType.IsEntityType ) { ! throw new QueryException( ! "collection of values in from clause: " + path ! ); ! } ! EntityType elemType = ( EntityType ) collectionElementType; ! System.Type clazz = elemType.PersistentClass; ! CollectionPersister persister = q.GetCollectionPersister( collectionRole ); ! string elementName; ! if( persister.IsOneToMany ) ! { ! elementName = collectionName; } else { ! q.AddCollection( collectionName, collectionRole ); ! IQueryable p = q.GetPersister( clazz ); ! elementName = q.CreateNameFor( clazz ); ! string[ ] keyColumnNames = p.IdentifierColumnNames; ! join.AddJoin( p.TableName, elementName, collectionElementColumns, keyColumnNames, joinType ); } - q.AddFrom( elementName, clazz, join ); - - return elementName; } --- 626,669 ---- public string AddFromCollection( QueryTranslator q ) { + IType collectionElementType = PropertyType; + if( collectionElementType == null ) { ! throw new QueryException( string.Format( "must specify 'elements' for collection valued property in from clause: {0}", path ) ); } ! if( collectionElementType.IsEntityType ) { ! // an association ! IQueryableCollection collectionPersister = q.GetCollectionPersister( collectionRole ); ! IQueryable entityPersister = (IQueryable) collectionPersister.ElementPersister; ! System.Type clazz = entityPersister.MappedClass; ! string[] collectionElementColumns = CurrentColumns(); ! ! string elementName; ! if ( collectionPersister.IsOneToMany ) ! { ! elementName = collectionName; ! // allow index() function ! q.DecoratePropertyMapping( elementName, collectionPersister ); ! } ! else ! { ! // many to many ! q.AddCollection( collectionName, collectionRole ); ! elementName = q.CreateNameFor( clazz ); ! string[] keyColumnNames = entityPersister.IdentifierColumnNames; ! join.AddJoin( entityPersister.TableName, elementName, collectionElementColumns, keyColumnNames, joinType ); ! } ! q.AddFrom( elementName, clazz, join ); ! currentPropertyMapping = new CollectionPropertyMapping( collectionPersister ); ! return elementName; } else { ! // collection of values ! q.AddFromCollection( collectionName, collectionRole, join ); ! return collectionName; } } *************** *** 645,735 **** /// <summary></summary> ! public string CollectionTable { ! get { return collectionTable; } } ! private void DoCollectionProperty( string token, CollectionPersister memberPersister, string name ) { ! if( token.Equals( CollectionElements ) ) ! { ! string[ ] cols = memberPersister.ElementColumnNames; ! collectionElementColumns = StringHelper.Prefix( cols, name + StringHelper.Dot ); ! collectionElementType = memberPersister.ElementType; ! } ! else if( token.Equals( CollectionIndices ) ) ! { ! if( !memberPersister.HasIndex ) ! { ! throw new QueryException( "unindexed collection before .indices" ); ! } ! string[ ] cols = memberPersister.IndexColumnNames; ! collectionElementColumns = StringHelper.Prefix( cols, name + StringHelper.Dot ); ! collectionElementType = memberPersister.IndexType; ! } ! else if( token.Equals( CollectionSize ) ) ! { ! collectionElementColumns = new string[ ] {"count(*)"}; ! collectionElementType = NHibernateUtil.Int32; ! } ! else if( token.Equals( CollectionMaxIndex ) ) ! { ! if( !memberPersister.HasIndex ) ! { ! throw new QueryException( "unindexed collection before .maxIndex" ); ! } ! string[ ] cols = memberPersister.IndexColumnNames; ! if( cols.Length != 1 ) ! { ! throw new QueryException( "composite collection index in maxIndex" ); ! } ! collectionElementColumns = new string[ ] {"max(" + cols[ 0 ] + StringHelper.ClosedParen}; ! collectionElementType = memberPersister.IndexType; ! } ! else if( token.Equals( CollectionMinIndex ) ) ! { ! if( !memberPersister.HasIndex ) ! { ! throw new QueryException( "unindexed collection before .minIndex" ); ! } ! string[ ] cols = memberPersister.IndexColumnNames; ! if( cols.Length != 1 ) ! { ! throw new QueryException( "composite collection index in minIndex" ); ! } ! collectionElementColumns = new string[ ] {"min(" + cols[ 0 ] + StringHelper.ClosedParen}; ! collectionElementType = memberPersister.IndexType; ! } ! else if( token.Equals( CollectionMaxElement ) ) ! { ! string[ ] cols = memberPersister.ElementColumnNames; ! if( cols.Length != 1 ) ! { ! throw new QueryException( "composite collection element in maxElement" ); ! } ! collectionElementColumns = new string[ ] {"max(" + cols[ 0 ] + StringHelper.ClosedParen}; ! collectionElementType = memberPersister.ElementType; ! } ! else if( token.Equals( CollectionMinElement ) ) { ! string[ ] cols = memberPersister.ElementColumnNames; ! if( cols.Length != 1 ) ! { ! throw new QueryException( "composite collection element in minElement" ); ! } ! collectionElementColumns = new string[ ] {"min(" + cols[ 0 ] + StringHelper.ClosedParen}; ! collectionElementType = memberPersister.ElementType; } else { ! throw new QueryException( "expecting 'elements' or 'indices' after " + path ); } } - - /// <summary></summary> - public String CollectionOwnerName - { - get { return collectionOwnerName; } - } } } \ No newline at end of file --- 681,717 ---- /// <summary></summary> ! public String CollectionOwnerName { ! get { return collectionOwnerName; } } ! /// <summary></summary> ! public string CurrentName { ! get { return currentName; } ! } ! ! /// <summary></summary> ! public string CurrentProperty ! { ! get { return currentProperty; } ! } ! ! /// <summary> ! /// ! /// </summary> ! /// <param name="q"></param> ! /// <param name="entityName"></param> ! public void Fetch( QueryTranslator q, string entityName ) ! { ! if ( IsCollectionValued ) { ! q.SetCollectionToFetch( CollectionRole, CollectionName, CollectionOwnerName, entityName ); } else { ! q.AddEntityToFetch( entityName, oneToOneOwnerName ); } } } } \ No newline at end of file Index: FromParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/FromParser.cs,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** FromParser.cs 31 Dec 2004 18:23:05 -0000 1.12 --- FromParser.cs 1 Mar 2005 16:24:46 -0000 1.13 *************** *** 262,273 **** ParserHelper.Parse( peParser, q.Unalias( token ), ParserHelper.PathSeparators, q ); ! if( peParser.IsCollectionValued ) ! { ! entityName = peParser.AddFromCollection( q ); ! } ! else ! { ! entityName = peParser.AddFromAssociation( q ); ! } joinType = JoinType.None; peParser.JoinType = JoinType.InnerJoin; --- 262,267 ---- ParserHelper.Parse( peParser, q.Unalias( token ), ParserHelper.PathSeparators, q ); ! entityName = peParser.AddFromAssociation( q ); ! joinType = JoinType.None; peParser.JoinType = JoinType.InnerJoin; *************** *** 275,284 **** if( afterFetch ) { ! if( peParser.IsCollectionValued ) ! { ! q.SetCollectionToFetch( peParser.CollectionRole, peParser.CollectionName, peParser.CollectionOwnerName ); ! } ! q.AddEntityToFetch( entityName ); ! afterFetch = false; } --- 269,273 ---- if( afterFetch ) { ! peParser.Fetch( q, entityName ); afterFetch = false; } Index: SelectPathExpressionParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/SelectPathExpressionParser.cs,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** SelectPathExpressionParser.cs 31 Dec 2004 18:22:14 -0000 1.5 --- SelectPathExpressionParser.cs 1 Mar 2005 16:24:46 -0000 1.6 *************** *** 10,14 **** public override void End( QueryTranslator q ) { ! if( currentProperty != null && !q.IsShallowQuery ) { // "finish off" the join --- 10,14 ---- public override void End( QueryTranslator q ) { ! if( CurrentProperty != null && !q.IsShallowQuery ) { // "finish off" the join *************** *** 28,32 **** public string SelectName { ! get { return currentName; } } } --- 28,32 ---- public string SelectName { ! get { return CurrentName; } } } Index: SelectParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/SelectParser.cs,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** SelectParser.cs 17 Jan 2005 03:40:57 -0000 1.11 --- SelectParser.cs 1 Mar 2005 16:24:46 -0000 1.12 *************** *** 2,5 **** --- 2,6 ---- using System.Collections; using Iesi.Collections; + using NHibernate.Dialect; using NHibernate.Type; using NHibernate.Util; *************** *** 39,42 **** --- 40,44 ---- private bool afterNew; private bool insideNew; + private bool aggregateAddSelectScalar; private System.Type holderClass; *************** *** 145,150 **** } //special case } ! else if( aggregateFunctions.Contains( lctoken ) ) { if( !ready ) { --- 147,153 ---- } //special case } ! else if ( GetFunction( lctoken, q ) != null && token == q.Unalias( token ) ) { + // the name of an SQL function if( !ready ) { *************** *** 152,155 **** --- 155,159 ---- } aggregate = true; + aggregateAddSelectScalar = true; aggregateFuncTokenList.Insert( 0, lctoken ); ready = false; *************** *** 172,194 **** } } - } else if( aggregate ) { if( !ready ) { throw new QueryException( "( expected after aggregate function in SELECT" ); } ! ParserHelper.Parse( aggregatePathExpressionParser, q.Unalias( token ), ParserHelper.PathSeparators, q ); ! if( aggregatePathExpressionParser.IsCollectionValued ) { ! q.AddCollection( ! aggregatePathExpressionParser.CollectionName, ! aggregatePathExpressionParser.CollectionRole ); } - q.AppendScalarSelectToken( aggregatePathExpressionParser.WhereColumn ); - q.AddSelectScalar( AggregateType( aggregateFuncTokenList, aggregatePathExpressionParser.WhereColumnType, q ) ); - aggregatePathExpressionParser.AddAssociation( q ); } else --- 176,216 ---- } } } else if( aggregate ) { + bool constantToken = false; if( !ready ) { throw new QueryException( "( expected after aggregate function in SELECT" ); } ! try ! { ! ParserHelper.Parse( aggregatePathExpressionParser, q.Unalias( token ), ParserHelper.PathSeparators, q ); ! } ! catch (QueryException) ! { ! constantToken = true; ! } ! if( constantToken ) { ! q.AppendScalarSelectToken( token ); ! } ! else ! { ! if( aggregatePathExpressionParser.IsCollectionValued ) ! { ! q.AddCollection( ! aggregatePathExpressionParser.CollectionName, ! aggregatePathExpressionParser.CollectionRole ); ! } ! q.AppendScalarSelectToken( aggregatePathExpressionParser.WhereColumn ); ! if( aggregateAddSelectScalar ) ! { ! q.AddSelectScalar( AggregateType( aggregateFuncTokenList, aggregatePathExpressionParser.WhereColumnType, q ) ); ! aggregateAddSelectScalar = false; ! } ! aggregatePathExpressionParser.AddAssociation( q ); } } else *************** *** 226,232 **** public bool AggregateHasArgs( String funcToken, QueryTranslator q ) { ! IDictionary funcMap = q.AggregateFunctions; ! IQueryFunctionInfo funcInfo = ( IQueryFunctionInfo ) funcMap[ funcToken ]; ! return funcInfo.IsFunctionArgs; } --- 248,252 ---- public bool AggregateHasArgs( String funcToken, QueryTranslator q ) { ! return GetFunction( funcToken, q ).HasArguments; } *************** *** 237,245 **** /// <param name="q"></param> /// <returns></returns> ! public bool AggregateFuncNoArgsHasParenthesis( String funcToken, QueryTranslator q ) { ! IDictionary funcMap = q.AggregateFunctions; ! IQueryFunctionInfo funcInfo = ( IQueryFunctionInfo ) funcMap[ funcToken ]; ! return funcInfo.IsFunctionNoArgsUseParanthesis; } --- 257,263 ---- /// <param name="q"></param> /// <returns></returns> ! public bool AggregateFuncNoArgsHasParenthesis( string funcToken, QueryTranslator q ) { ! return GetFunction( funcToken, q ).HasParenthesesIfNoArguments; } *************** *** 253,257 **** public IType AggregateType( ArrayList funcTokenList, IType type, QueryTranslator q ) { - IDictionary funcMap = q.AggregateFunctions; IType argType = type; IType retType = type; --- 271,274 ---- *************** *** 259,269 **** { argType = retType; ! String funcToken = ( String ) funcTokenList[ i ]; ! IQueryFunctionInfo funcInfo = ( IQueryFunctionInfo ) funcMap[ funcToken ]; ! retType = funcInfo.QueryFunctionType( argType, q.factory ); } return retType; } /// <summary> /// --- 276,290 ---- { argType = retType; ! string funcToken = ( string ) funcTokenList[ i ]; ! retType = GetFunction( funcToken, q ).ReturnType( argType, q.factory ) ; } return retType; } + private ISQLFunction GetFunction( string name, QueryTranslator q ) + { + return (ISQLFunction) q.Functions[ name ]; + } + /// <summary> /// *************** *** 278,282 **** holderClass = null; aggregateFuncTokenList.Clear(); - aggregateFunctions = q.AggregateFunctions; } --- 299,302 ---- Index: WhereParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/WhereParser.cs,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** WhereParser.cs 30 Jan 2005 19:39:12 -0000 1.28 --- WhereParser.cs 1 Mar 2005 16:24:46 -0000 1.29 *************** *** 25,29 **** private PathExpressionParser pathExpressionParser = new PathExpressionParser(); - private static ISet expressionTerminators = new HashedSet(); //tokens that close a sub expression private static ISet expressionOpeners = new HashedSet(); //tokens that open a sub expression --- 25,28 ---- *************** *** 177,181 **** { //ie. a many-to-many ! clazz = ( ( EntityType ) type ).PersistentClass; name = pathExpressionParser.ContinueFromManyToMany( clazz, element.ElementColumns, q ); } --- 176,180 ---- { //ie. a many-to-many ! clazz = ( ( EntityType ) type ).AssociatedClass; name = pathExpressionParser.ContinueFromManyToMany( clazz, element.ElementColumns, q ); } *************** *** 218,255 **** if( expectingPathContinuation ) { ! expectingPathContinuation = false; ! ! PathExpressionParser.CollectionElement element = pathExpressionParser.LastCollectionElement(); ! ! if( token.StartsWith( "." ) ) ! { // the path expression continues after a ] ! ! DoPathExpression( GetElementName( element, q ) + token, q ); // careful with this! ! ! AddToCurrentJoin( element ); ! return; //NOTE: EARLY EXIT! ! ! } ! else if( token.Equals( "[" ) ) ! { ! DoPathExpression( GetElementName( element, q ), q ); ! AddToCurrentJoin( element ); ! return; //NOTE: EARLY EXIT! ! } ! else ! { ! // the path expression ends at the ] ! if( element.ElementColumns.Length != 1 ) ! { ! throw new QueryException( "path expression ended in composite collection element" ); ! } ! AppendToken( q, element.ElementColumns[ 0 ] ); ! AddToCurrentJoin( element ); ! } ! } //Cope with a subselect - if( !inSubselect && ( lcToken.Equals( "select" ) || lcToken.Equals( "from" ) ) ) { --- 217,224 ---- if( expectingPathContinuation ) { ! if ( ContinuePathExpression( token, q ) ) return; } //Cope with a subselect if( !inSubselect && ( lcToken.Equals( "select" ) || lcToken.Equals( "from" ) ) ) { *************** *** 261,265 **** bracketsSinceSelect--; ! if( bracketsSinceSelect == - 1 ) { QueryTranslator subq = new QueryTranslator( d ); --- 230,234 ---- bracketsSinceSelect--; ! if( bracketsSinceSelect == -1 ) { QueryTranslator subq = new QueryTranslator( d ); *************** *** 313,317 **** //process a token, mapping OO path expressions to SQL expressions - DoToken( token, q ); --- 282,285 ---- *************** *** 324,330 **** //Cope with special cases of AND, NOT, ) - SpecialCasesAfter( lcToken ); - } --- 292,296 ---- *************** *** 375,380 **** joins.RemoveAt( joins.Count - 1 ); AppendToken( q, lastJoin.ToString() ); - - } else --- 341,344 ---- *************** *** 430,434 **** } - private void DoPathExpression( string token, QueryTranslator q ) { --- 394,397 ---- *************** *** 442,451 **** } pathExpressionParser.End( q ); if( pathExpressionParser.IsCollectionValued ) { ! OpenExpression( q, String.Empty ); AppendToken( q, pathExpressionParser.GetCollectionSubquery() ); ! q.AddIdentifierSpace( pathExpressionParser.CollectionTable ); ! CloseExpression( q, String.Empty ); } else --- 405,416 ---- } pathExpressionParser.End( q ); + if( pathExpressionParser.IsCollectionValued ) { ! OpenExpression( q, string.Empty ); AppendToken( q, pathExpressionParser.GetCollectionSubquery() ); ! CloseExpression( q, string.Empty ); ! // this is ugly here, but needed because its a subquery ! q.AddQuerySpace( q.GetCollectionPersister( pathExpressionParser.CollectionRole ).CollectionSpace ); } else *************** *** 494,501 **** else { ! IQueryable p = q.GetPersisterUsingImports( token ); ! if( p != null ) // the name of a class { ! AppendToken( q, p.DiscriminatorSQLString ); } else --- 459,466 ---- else { ! IQueryable persister = q.GetPersisterUsingImports( token ); ! if( persister != null ) // the name of a class { ! AppendToken( q, persister.DiscriminatorSQLString ); } else *************** *** 509,512 **** --- 474,479 ---- // don't even bother to do the lookups if the indexOfDot is not // greater than -1. This will save all the string modifications. + + // This allows us to resolve to the full type before obtaining the value e.g. FooStatus.OFF -> NHibernate.Model.FooStatus.OFF if( indexOfDot > -1 ) { *************** *** 531,534 **** --- 498,506 ---- } + if ( type == null ) + { + throw new QueryException( string.Format( "Could not determin the type of: {0}", token ) ); + } + try { *************** *** 623,626 **** --- 595,626 ---- } } + + private bool ContinuePathExpression( string token, QueryTranslator q ) + { + expectingPathContinuation = false; + + PathExpressionParser.CollectionElement element = pathExpressionParser.LastCollectionElement(); + + if( token.StartsWith( "." ) ) + { // the path expression continues after a ] + + DoPathExpression( GetElementName( element, q ) + token, q ); // careful with this! + + AddToCurrentJoin( element ); + return true; //NOTE: EARLY EXIT! + + } + else + { + // the path expression ends at the ] + if( element.ElementColumns.Length != 1 ) + { + throw new QueryException( "path expression ended in composite collection element" ); + } + AppendToken( q, element.ElementColumns[ 0 ] ); + AddToCurrentJoin( element ); + return false; + } + } } } \ No newline at end of file Index: FromPathExpressionParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/FromPathExpressionParser.cs,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** FromPathExpressionParser.cs 31 Dec 2004 18:23:05 -0000 1.6 --- FromPathExpressionParser.cs 1 Mar 2005 16:24:46 -0000 1.7 *************** *** 16,20 **** if( !IsCollectionValued ) { ! IType type = GetPropertyType( q ); if( type.IsEntityType ) { --- 16,20 ---- if( !IsCollectionValued ) { ! IType type = PropertyType; if( type.IsEntityType ) { Index: QueryTranslator.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/QueryTranslator.cs,v retrieving revision 1.54 retrieving revision 1.55 diff -C2 -d -r1.54 -r1.55 *** QueryTranslator.cs 14 Feb 2005 03:27:39 -0000 1.54 --- QueryTranslator.cs 1 Mar 2005 16:24:46 -0000 1.55 *************** *** 22,81 **** public class QueryTranslator : Loader.Loader { ! private static readonly ILog log = LogManager.GetLogger( typeof( QueryTranslator ) ); private IDictionary typeMap = new SequencedHashMap(); private IDictionary collections = new SequencedHashMap(); ! private IList returnTypes = new ArrayList(); private IList fromTypes = new ArrayList(); private IList scalarTypes = new ArrayList(); private IDictionary namedParameters = new Hashtable(); [...994 lines suppressed...] + /// <summary></summary> protected bool Compiled *************** *** 1537,1543 **** /// <summary></summary> ! public IDictionary AggregateFunctions { ! get { return factory.Dialect.AggregateFunctions; } } --- 1625,1631 ---- /// <summary></summary> ! public IDictionary Functions { ! get { return factory.Dialect.Functions; } } Index: OrderByParser.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/OrderByParser.cs,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** OrderByParser.cs 31 Dec 2004 18:22:33 -0000 1.6 --- OrderByParser.cs 1 Mar 2005 16:24:46 -0000 1.7 *************** *** 31,34 **** --- 31,42 ---- pathExpressionParser.AddAssociation( q ); } + else if ( token.StartsWith( ParserHelper.HqlVariablePrefix ) ) + { + q.AddNamedParameter( token.Substring( 1 ) ); + // this is only a temporary parameter to help with the parsing of hql - + // when the type becomes known then this will be converted to its real + // parameter type. + //AppendToken( q, new SqlString( new object[ ] {new Parameter( StringHelper.SqlParameter )} ) ); + } else { Index: FilterTranslator.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Hql/FilterTranslator.cs,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** FilterTranslator.cs 31 Dec 2004 18:23:33 -0000 1.9 --- FilterTranslator.cs 1 Mar 2005 16:24:46 -0000 1.10 *************** *** 26,30 **** { this.factory = factory; // yick! ! AddFromCollection( "this", collectionRole ); base.Compile( factory, queryString, replacements, scalar ); } --- 26,30 ---- { this.factory = factory; // yick! ! AddFromAssociation( "this", collectionRole ); base.Compile( factory, queryString, replacements, scalar ); } |