From: Michael D. <mik...@us...> - 2004-08-28 04:18:50
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29864/src/NHibernate/Impl Modified Files: BatcherImpl.cs NonBatchingBatcher.cs Log Message: Modified Batcher implementation to be more .net and synched with h2.0.3 Index: BatcherImpl.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl/BatcherImpl.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** BatcherImpl.cs 10 Feb 2004 18:31:55 -0000 1.2 --- BatcherImpl.cs 28 Aug 2004 04:18:40 -0000 1.3 *************** *** 1,9 **** using System; - using System.Data; using System.Collections; ! using NHibernate.Engine; ! namespace NHibernate.Impl { /// <summary> /// Manages prepared statements and batching. Class exists to enfores seperation of concerns --- 1,11 ---- using System; using System.Collections; ! using System.Data; ! using NHibernate.Engine; ! using NHibernate.SqlCommand; + namespace NHibernate.Impl + { /// <summary> /// Manages prepared statements and batching. Class exists to enfores seperation of concerns *************** *** 22,32 **** /// would be because I don't want to even think about writing that code :) /// </summary> ! internal abstract class BatcherImpl : IBatcher { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(BatcherImpl)); ! public static int open; ! protected ISessionImplementor session; ! protected ISessionFactoryImplementor factory; // batchCommand used to be called batchUpdate - that name to me implied that updates --- 24,36 ---- /// would be because I don't want to even think about writing that code :) /// </summary> ! internal abstract class BatcherImpl : IBatcher ! { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(BatcherImpl)); ! private static int openCommandCount; ! private static int openReaderCount; ! protected readonly ISessionImplementor session; ! protected readonly ISessionFactoryImplementor factory; // batchCommand used to be called batchUpdate - that name to me implied that updates *************** *** 34,42 **** // just update. However I haven't seen this being used with read statements... private IDbCommand batchCommand; ! private string batchCommandSQL; ! private ArrayList statementsToClose = new ArrayList(); ! public BatcherImpl(ISessionImplementor session) { this.session = session; this.factory = session.Factory; --- 38,48 ---- // just update. However I haven't seen this being used with read statements... private IDbCommand batchCommand; ! private SqlString batchCommandSql; ! private ArrayList commandsToClose = new ArrayList(); ! private ArrayList readersToClose = new ArrayList(); ! public BatcherImpl(ISessionImplementor session) ! { this.session = session; this.factory = session.Factory; *************** *** 60,183 **** /// </remarks> /// <returns></returns> ! protected IDbCommand GetStatement() { return batchCommand; } ! public IDbCommand PrepareStatement(string sql) { ExecuteBatch(); ! LogOpen(); ! return JoinTransaction( factory.GetPreparedStatement( session.Connection, sql, false) ); } ! public IDbCommand PrepareQueryStatement(string sql) { ! LogOpen(); ! IDbCommand command = factory.GetPreparedStatement( session.Connection, sql, false ); factory.SetFetchSize(command); ! statementsToClose.Add(command); ! return JoinTransaction(command); } ! /// <summary> ! /// Joins the Command to the Transaction and ensures that the Session and IDbCommand are in ! /// the same Transaction. ! /// </summary> ! /// <param name="command">The command to setup the Transaction on.</param> ! /// <returns>A IDbCommand with a valid Transaction property.</returns> ! private IDbCommand JoinTransaction(IDbCommand command) { ! IDbTransaction sessionAdoTrx = null; ! ! // at this point in the code if the Transaction is not null then we know we ! // have a Transaction object that has the .AdoTransaction property. In the future ! // we will have a seperate object to represent an AdoTransaction and won't have a ! // generic Transaction class - the existing Transaction class will become Abstract. ! if(this.session.Transaction!=null) sessionAdoTrx = ((Transaction.Transaction)session.Transaction).AdoTransaction; ! // if the sessionAdoTrx is null then we don't want the command to be a part of ! // any Transaction - so lets set the command trx to null ! if(sessionAdoTrx==null) { ! ! if(command.Transaction!=null) log.Warn("set a nonnull IDbCommand.Transaction to null because the Session had no Transaction"); ! command.Transaction = null; ! } ! // make sure these are the same transaction - I don't know why we would have a command ! // in a different Transaction than the Session, but I don't understand all of the code ! // well enough yet to verify that. ! else if (sessionAdoTrx!=command.Transaction) { ! // got into here because the command was being initialized and had a null Transaction - probably ! // don't need to be confused by that - just a normal part of initialization... ! log.Warn("The IDbCommand had a different Transaction than the Session. What is going on???"); ! command.Transaction = sessionAdoTrx; } - - return command; - } - - public void CloseQueryStatement(IDbCommand st) { - statementsToClose.Remove(st); - LogClose(); - factory.ClosePreparedStatement(st); - } - - public void CloseStatement(IDbCommand ps) { - LogClose(); - factory.ClosePreparedStatement(ps); } ! public IDbCommand PrepareBatchStatement(string sql) { ! if ( !sql.Equals(batchCommandSQL) ) { ! batchCommand = PrepareStatement(sql); ! batchCommandSQL=sql; } return batchCommand; } ! public void ExecuteBatch() { ! if ( batchCommand!=null ) { IDbCommand ps = batchCommand; batchCommand = null; ! batchCommandSQL = null; ! try { DoExecuteBatch(ps); ! } finally { ! CloseStatement(ps); } } } ! public void CloseStatements() { ! foreach( IDbCommand cmd in statementsToClose ) { ! try { ! CloseStatement(cmd); ! } catch(Exception e) { // no big deal log.Warn("Could not close a JDBC statement", e); } } ! statementsToClose.Clear(); } protected abstract void DoExecuteBatch(IDbCommand ps) ; ! public abstract void AddToBatch(int expectedCount); ! private static void LogOpen() { ! if ( log.IsDebugEnabled ) { ! open++; ! log.Debug( open + " open PreparedStatements" ); } } ! private static void LogClose() { ! if ( log.IsDebugEnabled ) ! open--; } } --- 66,265 ---- /// </remarks> /// <returns></returns> ! protected IDbCommand GetCommand() ! { return batchCommand; } ! public IDbCommand PrepareCommand(SqlString sql) ! { ExecuteBatch(); ! LogOpenPreparedCommands(); ! //return JoinTransaction( factory.GetPreparedStatement( session.Connection, sql, false) ); ! return session.Preparer.PrepareCommand(sql); } ! ! public IDbCommand PrepareQueryCommand(SqlString sql, bool scrollable) ! { ! //TODO: figure out what to do with scrollable - don't think it applies ! // to ado.net since DataReader is forward only ! LogOpenPreparedCommands(); ! IDbCommand command = session.Preparer.PrepareCommand(sql); ! //factory.GetPreparedStatement( session.Connection, sql, false ); + // not sure if this is needed because fetch size doesn't apply factory.SetFetchSize(command); ! commandsToClose.Add(command); ! return command; } ! public void AbortBatch(Exception e) { ! // log the exception here ! IDbCommand cmd = batchCommand; ! batchCommand = null; ! batchCommandSql = null; ! // close the statement closeStatement(cmd) ! } + public IDataReader GetDataReader(IDbCommand cmd) + { + IDataReader reader = cmd.ExecuteReader(); + readersToClose.Add(reader); + LogOpenReaders(); + return reader; + } ! public void CloseQueryCommand(IDbCommand st, IDataReader reader) ! { ! commandsToClose.Remove(st); ! if( reader!=null ) { ! readersToClose.Remove(reader); } ! try { ! if( reader!=null) ! { ! LogCloseReaders(); ! reader.Close(); ! } ! } ! finally ! { ! CloseQueryCommand(st); } } ! public IDbCommand PrepareBatchCommand(SqlString sql) ! { ! if ( !sql.Equals(batchCommandSql) ) ! { ! batchCommand = PrepareCommand(sql); // calls ExecuteBatch() ! batchCommandSql=sql; } return batchCommand; } ! public void ExecuteBatch() ! { ! if ( batchCommand!=null ) ! { IDbCommand ps = batchCommand; batchCommand = null; ! batchCommandSql = null; ! try ! { DoExecuteBatch(ps); ! } ! finally ! { ! CloseCommand(ps); } } } ! public void CloseCommand(IDbCommand cmd) ! { ! LogClosePreparedCommands(); ! // factory.ClosePreparedStatement(cmd); ! } ! ! private void CloseQueryCommand(IDbCommand cmd) ! { ! try ! { ! // no equiv to the java code in here ! } ! catch( Exception e ) ! { ! log.Warn( "exception clearing maxRows/queryTimeout", e ); ! //cmd.close(); if there was a close method in command ! return; // NOTE: early exit! ! } ! ! CloseCommand( cmd ); ! } ! ! public void CloseCommands() ! { ! foreach( IDataReader reader in readersToClose ) ! { ! try ! { ! LogCloseReaders(); ! reader.Close(); ! } ! catch( Exception e ) ! { ! log.Warn( "Could not close IDataReader", e ); ! } ! } ! readersToClose.Clear(); ! ! foreach( IDbCommand cmd in commandsToClose ) ! { ! try ! { ! CloseQueryCommand(cmd); ! } ! catch(Exception e) ! { // no big deal log.Warn("Could not close a JDBC statement", e); } } ! commandsToClose.Clear(); } protected abstract void DoExecuteBatch(IDbCommand ps) ; ! public abstract void AddToBatch(int expectedRowCount); ! protected ISessionFactoryImplementor Factory ! { ! get { return factory; } ! } ! ! protected ISessionImplementor Session ! { ! get { return session; } ! } ! ! private static void LogOpenPreparedCommands() ! { ! if ( log.IsDebugEnabled ) ! { ! log.Debug( "about to open: " + openCommandCount + " open IDbCommands, " + openReaderCount + " open DataReaders" ); ! openCommandCount++; } } ! private static void LogClosePreparedCommands() ! { ! if ( log.IsDebugEnabled ) ! { ! openCommandCount--; ! log.Debug( "done closing: " + openCommandCount + " open IDbCommands, " + openReaderCount + " open DataReaders" ); ! } ! } ! ! private static void LogOpenReaders() ! { ! if( log.IsDebugEnabled ) ! { ! openReaderCount++; ! } ! } ! ! private static void LogCloseReaders() ! { ! if( log.IsDebugEnabled ) ! { ! openReaderCount--; ! } } } Index: NonBatchingBatcher.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Impl/NonBatchingBatcher.cs,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** NonBatchingBatcher.cs 10 Feb 2004 18:31:55 -0000 1.4 --- NonBatchingBatcher.cs 28 Aug 2004 04:18:40 -0000 1.5 *************** *** 7,42 **** /// An implementation of the <c>IBatcher</c> inteface that does no batching /// </summary> ! internal class NonBatchingBatcher : BatcherImpl { ! public NonBatchingBatcher(ISessionImplementor session) : base(session) { } ! ! public override void AddToBatch(int expectedRowCount) { ! ! IDbCommand command = GetStatement(); ! ! // this should not be needed because all commands added to the Batcher should ! // have their Transaction property set. ! // Hack: join transaction ! //Impl.AdoHack.JoinTx(s); ! // end-of Hack ! ! // verify that the commands IDbTransaction and the Session.Transaction.IDbTransaction are the ! // same object ! // TODO: remove this copy and pasted code (in BatcherImpl.JoinTransaction) ! IDbTransaction sessionAdoTrx = null; ! if(this.session.Transaction!=null) sessionAdoTrx = ((Transaction.Transaction)session.Transaction).AdoTransaction; ! ! if(command.Transaction!= sessionAdoTrx) ! throw new HibernateException("In NonBatchingBatcher.AddToBatch there is a Command's IDbTransaction that is different than the Session.Transaction.AdoTransaction"); ! ! int rowCount = command.ExecuteNonQuery(); //negative expected row count means we don't know how many rows to expect ! if ( expectedRowCount>0 && expectedRowCount!=rowCount ) throw new HibernateException("SQL update or deletion failed (row not found)"); } ! protected override void DoExecuteBatch(IDbCommand ps) { } --- 7,30 ---- /// An implementation of the <c>IBatcher</c> inteface that does no batching /// </summary> ! internal class NonBatchingBatcher : BatcherImpl ! { ! public NonBatchingBatcher(ISessionImplementor session) : base(session) ! { ! } ! public override void AddToBatch(int expectedRowCount) ! { ! int rowCount = GetCommand().ExecuteNonQuery(); //negative expected row count means we don't know how many rows to expect ! if ( expectedRowCount>0 && expectedRowCount!=rowCount ) ! { throw new HibernateException("SQL update or deletion failed (row not found)"); + } } ! protected override void DoExecuteBatch(IDbCommand ps) ! { } |