From: <aye...@us...> - 2010-01-06 20:52:34
|
Revision: 4907 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4907&view=rev Author: ayenderahien Date: 2010-01-06 20:52:28 +0000 (Wed, 06 Jan 2010) Log Message: ----------- Applying patch for NH-2055 from Jason Dentler Modified Paths: -------------- branches/2.1.x/nhibernate/src/NHibernate/Dialect/Dialect.cs branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/SchemaExport.cs Added Paths: ----------- branches/2.1.x/nhibernate/src/NHibernate/Exceptions/SqlParseException.cs branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/ScriptSplitter.cs Modified: branches/2.1.x/nhibernate/src/NHibernate/Dialect/Dialect.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Dialect/Dialect.cs 2010-01-06 20:48:12 UTC (rev 4906) +++ branches/2.1.x/nhibernate/src/NHibernate/Dialect/Dialect.cs 2010-01-06 20:52:28 UTC (rev 4907) @@ -2105,5 +2105,17 @@ } } #endregion + + /// <summary> + /// Supports splitting batches using GO T-SQL command + /// </summary> + /// <remarks> + /// Batches http://msdn.microsoft.com/en-us/library/ms175502.aspx + /// </remarks> + public virtual bool SupportsSqlBatches + { + get { return false; } + } + } } Added: branches/2.1.x/nhibernate/src/NHibernate/Exceptions/SqlParseException.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Exceptions/SqlParseException.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate/Exceptions/SqlParseException.cs 2010-01-06 20:52:28 UTC (rev 4907) @@ -0,0 +1,13 @@ +using System; + +namespace NHibernate.Exceptions +{ + public class SqlParseException : Exception + { + + public SqlParseException(string Message) : base(Message) + { + } + + } +} Modified: branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj 2010-01-06 20:48:12 UTC (rev 4906) +++ branches/2.1.x/nhibernate/src/NHibernate/NHibernate.csproj 2010-01-06 20:52:28 UTC (rev 4907) @@ -489,6 +489,7 @@ <Compile Include="Event\IPreDatabaseOperationEventArgs.cs" /> <Compile Include="Exceptions\AdoExceptionContextInfo.cs" /> <Compile Include="Exceptions\ReflectionBasedSqlStateExtracter.cs" /> + <Compile Include="Exceptions\SqlParseException.cs" /> <Compile Include="Exceptions\SqlStateExtracter.cs" /> <Compile Include="Exceptions\TemplatedViolatedConstraintNameExtracter.cs" /> <Compile Include="Hql\Ast\ANTLR\ASTQueryTranslatorFactory.cs" /> @@ -614,6 +615,7 @@ <Compile Include="Proxy\AbstractProxyFactory.cs" /> <Compile Include="SqlCommand\InsertSelect.cs" /> <Compile Include="Tool\hbm2ddl\SchemaMetadataUpdater.cs" /> + <Compile Include="Tool\hbm2ddl\ScriptSplitter.cs" /> <Compile Include="Transaction\AdoNetWithDistrubtedTransactionFactory.cs" /> <Compile Include="Transform\ToListResultTransformer.cs" /> <Compile Include="Type\DbTimestampType.cs" /> Modified: branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/SchemaExport.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/SchemaExport.cs 2010-01-06 20:48:12 UTC (rev 4906) +++ branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/SchemaExport.cs 2010-01-06 20:52:28 UTC (rev 4907) @@ -127,9 +127,7 @@ } if (export) { - statement.CommandText = sql; - statement.CommandType = CommandType.Text; - statement.ExecuteNonQuery(); + ExecuteSql(statement, sql); } } catch (Exception e) @@ -143,6 +141,29 @@ } } + private void ExecuteSql(IDbCommand cmd, string sql) + { + if (dialect.SupportsSqlBatches) + { + var objFactory = Environment.BytecodeProvider.ObjectsFactory; + ScriptSplitter splitter = (ScriptSplitter)objFactory.CreateInstance(typeof(ScriptSplitter), sql); + + foreach (string stmt in splitter) + { + log.DebugFormat("SQL Batch: {0}", stmt); + cmd.CommandText = stmt; + cmd.CommandType = CommandType.Text; + cmd.ExecuteNonQuery(); + } + } + else + { + cmd.CommandText = sql; + cmd.CommandType = CommandType.Text; + cmd.ExecuteNonQuery(); + } + } + /// <summary> /// Executes the Export of the Schema in the given connection /// </summary> Added: branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/ScriptSplitter.cs =================================================================== --- branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/ScriptSplitter.cs (rev 0) +++ branches/2.1.x/nhibernate/src/NHibernate/Tool/hbm2ddl/ScriptSplitter.cs 2010-01-06 20:52:28 UTC (rev 4907) @@ -0,0 +1,405 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace NHibernate.Tool.hbm2ddl +{ + public class ScriptSplitter : IEnumerable<string> + { + private readonly TextReader _reader; + private StringBuilder _builder = new StringBuilder(); + private char _current; + private char _lastChar; + private ScriptReader _scriptReader; + + public ScriptSplitter(string script) + { + _reader = new StringReader(script); + _scriptReader = new SeparatorLineReader(this); + } + + internal bool HasNext + { + get { return _reader.Peek() != -1; } + } + + internal char Current + { + get { return _current; } + } + + internal char LastChar + { + get { return _lastChar; } + } + + #region IEnumerable<string> Members + + public IEnumerator<string> GetEnumerator() + { + while (Next()) + { + if (Split()) + { + string script = _builder.ToString().Trim(); + if (script.Length > 0) + { + yield return (script); + } + Reset(); + } + } + if (_builder.Length > 0) + { + string scriptRemains = _builder.ToString().Trim(); + if (scriptRemains.Length > 0) + { + yield return (scriptRemains); + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + internal bool Next() + { + if (!HasNext) + { + return false; + } + + _lastChar = _current; + _current = (char)_reader.Read(); + return true; + } + + internal int Peek() + { + return _reader.Peek(); + } + + private bool Split() + { + return _scriptReader.ReadNextSection(); + } + + internal void SetParser(ScriptReader newReader) + { + _scriptReader = newReader; + } + + internal void Append(string text) + { + _builder.Append(text); + } + + internal void Append(char c) + { + _builder.Append(c); + } + + void Reset() + { + _current = _lastChar = char.MinValue; + _builder = new StringBuilder(); + } + } + + abstract class ScriptReader + { + protected readonly ScriptSplitter Splitter; + + protected ScriptReader(ScriptSplitter splitter) + { + Splitter = splitter; + } + + /// <summary> + /// This acts as a template method. Specific Reader instances + /// override the component methods. + /// </summary> + public bool ReadNextSection() + { + if (IsQuote) + { + ReadQuotedString(); + return false; + } + + if (BeginDashDashComment) + { + return ReadDashDashComment(); + } + + if (BeginSlashStarComment) + { + ReadSlashStarComment(); + return false; + } + + return ReadNext(); + } + + protected virtual bool ReadDashDashComment() + { + Splitter.Append(Current); + while (Splitter.Next()) + { + Splitter.Append(Current); + if (EndOfLine) + { + break; + } + } + //We should be EndOfLine or EndOfScript here. + Splitter.SetParser(new SeparatorLineReader(Splitter)); + return false; + } + + protected virtual void ReadSlashStarComment() + { + if (ReadSlashStarCommentWithResult()) + { + Splitter.SetParser(new SeparatorLineReader(Splitter)); + return; + } + } + + private bool ReadSlashStarCommentWithResult() + { + Splitter.Append(Current); + while (Splitter.Next()) + { + if (BeginSlashStarComment) + { + ReadSlashStarCommentWithResult(); + continue; + } + Splitter.Append(Current); + + if (EndSlashStarComment) + { + return true; + } + } + return false; + } + + protected virtual void ReadQuotedString() + { + Splitter.Append(Current); + while (Splitter.Next()) + { + Splitter.Append(Current); + if (IsQuote) + { + return; + } + } + } + + protected abstract bool ReadNext(); + + #region Helper methods and properties + + protected bool HasNext + { + get { return Splitter.HasNext; } + } + + protected bool WhiteSpace + { + get { return char.IsWhiteSpace(Splitter.Current); } + } + + protected bool EndOfLine + { + get { return '\n' == Splitter.Current; } + } + + protected bool IsQuote + { + get { return '\'' == Splitter.Current; } + } + + protected char Current + { + get { return Splitter.Current; } + } + + protected char LastChar + { + get { return Splitter.LastChar; } + } + + bool BeginDashDashComment + { + get { return Current == '-' && Peek() == '-'; } + } + + bool BeginSlashStarComment + { + get { return Current == '/' && Peek() == '*'; } + } + + bool EndSlashStarComment + { + get { return LastChar == '*' && Current == '/'; } + } + + protected static bool CharEquals(char expected, char actual) + { + return Char.ToLowerInvariant(expected) == Char.ToLowerInvariant(actual); + } + + protected bool CharEquals(char compare) + { + return CharEquals(Current, compare); + } + + protected char Peek() + { + if (!HasNext) + { + return char.MinValue; + } + return (char)Splitter.Peek(); + } + + #endregion + } + + class SeparatorLineReader : ScriptReader + { + private StringBuilder _builder = new StringBuilder(); + private bool _foundGo; + private bool _gFound; + + public SeparatorLineReader(ScriptSplitter splitter) + : base(splitter) + { + } + + void Reset() + { + _foundGo = false; + _gFound = false; + _builder = new StringBuilder(); + } + + protected override bool ReadDashDashComment() + { + if (!_foundGo) + { + base.ReadDashDashComment(); + return false; + } + base.ReadDashDashComment(); + return true; + } + + protected override void ReadSlashStarComment() + { + if (_foundGo) + { + throw new NHibernate.Exceptions.SqlParseException(@"Incorrect syntax was encountered while parsing GO. Cannot have a slash star /* comment */ after a GO statement."); + } + base.ReadSlashStarComment(); + } + + protected override bool ReadNext() + { + if (EndOfLine) //End of line or script + { + if (!_foundGo) + { + _builder.Append(Current); + Splitter.Append(_builder.ToString()); + Splitter.SetParser(new SeparatorLineReader(Splitter)); + return false; + } + Reset(); + return true; + } + + if (WhiteSpace) + { + _builder.Append(Current); + return false; + } + + if (!CharEquals('g') && !CharEquals('o')) + { + FoundNonEmptyCharacter(Current); + return false; + } + + if (CharEquals('o')) + { + if (CharEquals('g', LastChar) && !_foundGo) + { + _foundGo = true; + } + else + { + FoundNonEmptyCharacter(Current); + } + } + + if (CharEquals('g', Current)) + { + if (_gFound || (!Char.IsWhiteSpace(LastChar) && LastChar != char.MinValue)) + { + FoundNonEmptyCharacter(Current); + return false; + } + + _gFound = true; + } + + if (!HasNext && _foundGo) + { + Reset(); + return true; + } + + _builder.Append(Current); + return false; + } + + void FoundNonEmptyCharacter(char c) + { + _builder.Append(c); + Splitter.Append(_builder.ToString()); + Splitter.SetParser(new SqlScriptReader(Splitter)); + } + } + + class SqlScriptReader : ScriptReader + { + public SqlScriptReader(ScriptSplitter splitter) + : base(splitter) + { + } + + protected override bool ReadNext() + { + if (EndOfLine) //end of line + { + Splitter.Append(Current); + Splitter.SetParser(new SeparatorLineReader(Splitter)); + return false; + } + + Splitter.Append(Current); + return false; + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |