/// <summary>
		/// Generate the SQL DELETE that deletes all rows
		/// </summary>
		/// <returns></returns>
		protected override SqlString GenerateDeleteString()
		{
			SqlDeleteBuilder delete = new SqlDeleteBuilder( factory )
				.SetTableName( qualifiedTableName )
				.SetIdentityColumn( KeyColumnNames, KeyType );
			if( HasWhere )
			{
				delete.AddWhereFragment( sqlWhereString );
			}
			return delete.ToSqlString();
		}
		public void DeleteSqlStringTest() {
			Configuration cfg = new Configuration();
			ISessionFactory factory = cfg.BuildSessionFactory( );

			ISessionFactoryImplementor factoryImpl = (ISessionFactoryImplementor)factory;
			SqlDeleteBuilder delete = new SqlDeleteBuilder(factoryImpl);
			
			delete.SetTableName("test_delete_builder");

			
			delete.SetIdentityColumn(new string[] {"decimalColumn"}, NHibernateUtil.Decimal);
			delete.SetVersionColumn(new string[] {"versionColumn"}, (IVersionType)NHibernateUtil.Int32);

			delete.AddWhereFragment("a=b");
			SqlString sqlString = delete.ToSqlString();
			Parameter[] actualParams = new Parameter[2];
			int numOfParameters = 0;
			

			string expectedSql = "DELETE FROM test_delete_builder WHERE decimalColumn = :decimalColumn AND versionColumn = :versionColumn AND a=b";
			Assert.AreEqual(expectedSql , sqlString.ToString(), "SQL String");
			
			foreach(object part in sqlString.SqlParts) {
				if(part is Parameter) {
					actualParams[numOfParameters] = (Parameter)part;
					numOfParameters++;
				}
			}
			Assert.AreEqual(2, numOfParameters, "Two parameters");


			Parameter firstParam = new Parameter( "decimalColumn", new SqlTypes.DecimalSqlType() );
			
			Parameter secondParam = new Parameter( "versionColumn", new SqlTypes.Int32SqlType());
			
			Assert.AreEqual(firstParam.SqlType.DbType, actualParams[0].SqlType.DbType, "firstParam Type");
			Assert.AreEqual(firstParam.Name, actualParams[0].Name, "firstParam Name");

			Assert.AreEqual(secondParam.SqlType.DbType, actualParams[1].SqlType.DbType, "secondParam Type");
			Assert.AreEqual(secondParam.Name, actualParams[1].Name, "secondParam Name");

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

			var deleteStatement = (DeleteStatement) statement;

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

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

			string[] tableNames = persister.ConstraintOrderedTableNameClosure;
			string[][] columnNames = persister.ContraintOrderedTableKeyColumnClosure;
			string idSubselect = GenerateIdSubselect(persister);

			deletes = new SqlString[tableNames.Length];
			for (int i = tableNames.Length - 1; i >= 0; i--)
			{
				// TODO : an optimization here would be to consider cascade deletes and not gen those delete statements;
				//      the difficulty is the ordering of the tables here vs the cascade attributes on the persisters ->
				//          the table info gotten here should really be self-contained (i.e., a class representation
				//          defining all the needed attributes), then we could then get an array of those
				SqlDeleteBuilder delete = new SqlDeleteBuilder(Factory.Dialect, Factory)
					.SetTableName(tableNames[i])
					.SetWhere("(" + StringHelper.Join(", ", columnNames[i]) + ") IN (" + idSubselect + ")");
				if (Factory.Settings.IsCommentsEnabled)
				{
					delete.SetComment("bulk delete");
				}

				deletes[i] = delete.ToSqlString();
			}
		}
		// Generate all the SQL

		/// <summary>
		/// Generate the SQL that deletes rows by id (and version)
		/// </summary>
		/// <returns>An array of SqlStrings</returns>
		protected virtual SqlString[ ] GenerateDeleteStrings()
		{
			SqlString[ ] deleteStrings = new SqlString[ naturalOrderTableNames.Length ];

			for( int i = 0; i < naturalOrderTableNames.Length; i++ )
			{
				SqlDeleteBuilder deleteBuilder = new SqlDeleteBuilder( factory );

				// TODO: find out why this is using tableKeyColumns and when
				// they would ever be different between the two tables - I thought
				// a requirement of Hibernate is that joined/subclassed tables
				// had to have the same pk - otherwise you had an association.
				deleteBuilder.SetTableName( naturalOrderTableNames[ i ] )
					.SetIdentityColumn( naturalOrderTableKeyColumns[ i ], IdentifierType );

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

				deleteStrings[ i ] = deleteBuilder.ToSqlString();
			}

			return deleteStrings;
		}
		/// <summary>
		/// Generate the SQL DELETE that deletes a particular row
		/// </summary>
		/// <returns></returns>
		protected override SqlString GenerateDeleteRowString()
		{
			SqlDeleteBuilder delete = new SqlDeleteBuilder( factory );
			delete.SetTableName( qualifiedTableName );
			if( hasIdentifier )
			{
				delete.AddWhereFragment( rowSelectColumnNames, rowSelectType, " = " );
			}
			else
			{
				delete.AddWhereFragment( KeyColumnNames, KeyType, " = " )
					.AddWhereFragment( rowSelectColumnNames, rowSelectType, " = " );
			}

			return delete.ToSqlString();
		}