public MultiTableUpdateExecutor(IStatement statement) : base(statement, log)
		{
			if (!Factory.Dialect.SupportsTemporaryTables)
			{
				throw new HibernateException("cannot perform multi-table updates using dialect not supporting temp tables");
			}
			var updateStatement = (UpdateStatement) statement;

			FromElement fromElement = updateStatement.FromClause.GetFromElement();
			string bulkTargetAlias = fromElement.TableAlias;
			persister = fromElement.Queryable;

			idInsertSelect = GenerateIdInsertSelect(persister, bulkTargetAlias, updateStatement.WhereClause);
			log.Debug("Generated ID-INSERT-SELECT SQL (multi-table update) : " + idInsertSelect);

			string[] tableNames = persister.ConstraintOrderedTableNameClosure;
			string[][] columnNames = persister.ConstraintOrderedTableKeyColumnClosure;

			string idSubselect = GenerateIdSubselect(persister);
			IList<AssignmentSpecification> assignmentSpecifications = Walker.AssignmentSpecifications;

			updates = new SqlString[tableNames.Length];
			hqlParameters = new IParameterSpecification[tableNames.Length][];
			for (int tableIndex = 0; tableIndex < tableNames.Length; tableIndex++)
			{
				bool affected = false;
				var parameterList = new List<IParameterSpecification>();
				SqlUpdateBuilder update =
					new SqlUpdateBuilder(Factory.Dialect, Factory).SetTableName(tableNames[tableIndex])
					.SetWhere(
						string.Format("({0}) IN ({1})", StringHelper.Join(", ", columnNames[tableIndex]), idSubselect));

				if (Factory.Settings.IsCommentsEnabled)
				{
					update.SetComment("bulk update");
				}
				foreach (var specification in assignmentSpecifications)
				{
					if (specification.AffectsTable(tableNames[tableIndex]))
					{
						affected = true;
						update.AppendAssignmentFragment(specification.SqlAssignmentFragment);
						if (specification.Parameters != null)
						{
							for (int paramIndex = 0; paramIndex < specification.Parameters.Length; paramIndex++)
							{
								parameterList.Add(specification.Parameters[paramIndex]);
							}
						}
					}
				}
				if (affected)
				{
					updates[tableIndex] = update.ToSqlString();
					hqlParameters[tableIndex] = parameterList.ToArray();
				}
			}
		}
		private SqlString GenerateLockString()
		{
			ISessionFactoryImplementor factory = lockable.Factory;
			SqlUpdateBuilder update = new SqlUpdateBuilder(factory.Dialect, factory);
			update.SetTableName(lockable.RootTableName);
			update.SetIdentityColumn(lockable.RootTableIdentifierColumnNames, lockable.IdentifierType);
			update.SetVersionColumn(new string[] { lockable.VersionColumnName }, lockable.VersionType);
			update.AddColumns(new string[] { lockable.VersionColumnName }, null, lockable.VersionType);
			if (factory.Settings.IsCommentsEnabled)
			{
				update.SetComment(lockMode + " lock " + lockable.EntityName);
			}
			return update.ToSqlString();
		}
		/// <summary>
		/// Generate the SQL UPDATE that updates a foreign key to a value
		/// </summary>
		/// <returns></returns>
		protected override SqlString GenerateInsertRowString( )
		{
			SqlUpdateBuilder update = new SqlUpdateBuilder( factory );
			update.SetTableName( qualifiedTableName )
				.AddColumns( KeyColumnNames, KeyType )
				.SetIdentityColumn( ElementColumnNames, ElementType );
			if( HasIndex )
			{
				update.AddColumns( IndexColumnNames, IndexType );
			}
			//identifier collections not supported for 1-to-many 

			return update.ToSqlString();
		}
		/// <summary>
		/// Generate the SQL UPDATE that updates all the foreign keys to null
		/// </summary>
		/// <returns></returns>
		protected override SqlString GenerateDeleteString( )
		{
			SqlUpdateBuilder update = new SqlUpdateBuilder( factory )
				.SetTableName( qualifiedTableName )
				.AddColumns( KeyColumnNames, "null" )
				.SetIdentityColumn( KeyColumnNames, KeyType );
			if( HasIndex )
			{
				update.AddColumns( IndexColumnNames, "null" );
			}
			if( HasWhere )
			{
				update.AddWhereFragment( sqlWhereString );
			}

			return update.ToSqlString();
		}
		/// <summary>
		/// Generate the SQL UPDATE that updates a row
		/// </summary>
		/// <returns></returns>
		protected override SqlString GenerateUpdateRowString()
		{
			SqlUpdateBuilder update = new SqlUpdateBuilder( factory )
				.SetTableName( qualifiedTableName )
				.AddColumns( ElementColumnNames, ElementType );
			if( hasIdentifier )
			{
				update.AddWhereFragment( rowSelectColumnNames, rowSelectType, " = " );
			}
			else
			{
				update.AddWhereFragment( KeyColumnNames, KeyType, " = " )
					.AddWhereFragment( rowSelectColumnNames, rowSelectType, " = " );
			}

			return update.ToSqlString();
		}
		/// <summary>
		/// Generate the SQL that updates rows by id (and version)
		/// </summary>
		/// <param name="includeProperty"></param>
		/// <returns>An array of SqlStrings</returns>
		protected virtual SqlString[ ] GenerateUpdateStrings( bool[ ] includeProperty )
		{
			SqlString[ ] results = new SqlString[naturalOrderTableNames.Length];

			for( int j = 0; j < naturalOrderTableNames.Length; j++ )
			{
				SqlUpdateBuilder updateBuilder = new SqlUpdateBuilder( factory )
					.SetTableName( naturalOrderTableNames[ j ] )
					.SetIdentityColumn( naturalOrderTableKeyColumns[ j ], IdentifierType );

				if( j == 0 && IsVersioned )
				{
					updateBuilder.SetVersionColumn( new string[ ] {VersionColumnName}, VersionType );
				}

				//TODO: figure out what the hasColumns variable comes into play for??
				bool hasColumns = false;
				for( int i = 0; i < propertyColumnNames.Length; i++ )
				{
					if( includeProperty[ i ] && naturalOrderPropertyTables[ i ] == j )
					{
						updateBuilder.AddColumns( propertyColumnNames[ i ], PropertyTypes[ i ] );
						hasColumns = hasColumns || propertyColumnNames[ i ].Length > 0;
					}
				}
				results[ j ] = hasColumns ?	updateBuilder.ToSqlString() : null;
			}

			return results;
		}