port batch parser wrapper (#232)

* Initial commit for GitHub IO pages

* Add initial doxfx content

* Update manifest.json

* Update manifest.json

* Set theme jekyll-theme-cayman

* Set theme jekyll-theme-slate

* Set theme jekyll-theme-minimal

* Set theme jekyll-theme-tactile

* Clear out theme setting

* Remove API docs

* Revert "Adding Milliseconds to DateTime fields (#173)" (#197)

This reverts commit 431dfa4156.

* ported new BatchParser

* added BatchParser tests

* fixing merge conflicts

* fix build issues

* cleaned code and addressed comments from code review

* addressed code review and made BatchParser logic more efficient

* fixed batch parser tests

* changed class name to fix build issues

* fixed merge conflicts

* added path for lab mode baseline tests

* changed env path for lab mode

* added env variable to appveyor

* testing env variable for appveyor

* fixed lab build

* debug appveyor build

* testing changes for appveyor

* changed trace env path

* debugging appveyor build

* changed baseline env path

* debugging

* debugging

* debugging

* switched on trace flag

* debugging

* debugging

* changed build config

* changed baseline files

* checking baseline output

* changed baseline files

* debug baseline tests

* debugging baseline

* debugging

* debugging

* debug

* debugging

* testing baseline format

* debug

* debug

* debug

* debug

* debug

* newline debug

* changed baseline file

* debug

* test

* try new way to read

* added execution engine tests

* change test

* testing file encoding

* moved execution engine tests to integration

* try compare without spaces

* removed no op test

* added env variable for travis

* put batch parser tests to integration too

* put batch parser in integration

* try new baseline string match

* compare baseline test logic changed

* changed baseline logic as well as cleaned tests

* fix build for travis CI

* fix travis CI issues

* fixed highlighting bugs on vscode

* code review changes

* ported new BatchParser

* added BatchParser tests

* Initial commit for GitHub IO pages

* Add initial doxfx content

* Update manifest.json

* Update manifest.json

* Set theme jekyll-theme-cayman

* Set theme jekyll-theme-slate

* Set theme jekyll-theme-minimal

* Set theme jekyll-theme-tactile

* Clear out theme setting

* Remove API docs

* Revert "Adding Milliseconds to DateTime fields (#173)" (#197)

This reverts commit 431dfa4156.

* fixing merge conflicts

* fix build issues

* cleaned code and addressed comments from code review

* addressed code review and made BatchParser logic more efficient

* fixed batch parser tests

* changed class name to fix build issues

* fixed merge conflicts

* added path for lab mode baseline tests

changed env path for lab mode

added env variable to appveyor

testing env variable for appveyor

fixed lab build

debug appveyor build

testing changes for appveyor

changed trace env path

debugging appveyor build

changed baseline env path

debugging

debugging

debugging

switched on trace flag

debugging

debugging

changed build config

changed baseline files

checking baseline output

changed baseline files

debug baseline tests

debugging baseline

debugging

debugging

debug

debugging

testing baseline format

debug

debug

debug

debug

debug

newline debug

changed baseline file

debug

test

try new way to read

added execution engine tests

change test

testing file encoding

moved execution engine tests to integration

try compare without spaces

removed no op test

added env variable for travis

* put batch parser tests to integration too

* put batch parser in integration

try new baseline string match

* compare baseline test logic changed

* changed baseline logic as well as cleaned tests

* fix build for travis CI

* fix travis CI issues

* fixed highlighting bugs on vscode

* code review changes

* fixed filestream writer test

* added localization string

* added localization string

* generated new string files again

* code review changes
This commit is contained in:
Aditya Bist
2017-02-10 16:51:26 -08:00
committed by GitHub
parent 1a5685c387
commit eb4f2f2b91
412 changed files with 82047 additions and 704 deletions

View File

@@ -0,0 +1,873 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Single batch of SQL command
/// </summary>
internal class Batch
{
#region Private methods
/// <summary>
/// Helper method to format the provided SqlError
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
private string FormatSqlErrorMessage(SqlError error)
{
string detailedMessage = string.Empty;
if (error.Class > 10)
{
if (string.IsNullOrEmpty(error.Procedure))
{
detailedMessage = string.Format(CultureInfo.CurrentCulture, SR.EE_BatchSqlMessageNoProcedureInfo,
error.Number,
error.Class,
error.State,
error.LineNumber);
}
else
{
detailedMessage = string.Format(CultureInfo.CurrentCulture, SR.EE_BatchSqlMessageWithProcedureInfo,
error.Number,
error.Class,
error.State,
error.Procedure,
error.LineNumber);
}
}
else if (error.Class > 0 && error.Number > 0)
{
detailedMessage = string.Format(CultureInfo.CurrentCulture, SR.EE_BatchSqlMessageNoLineInfo,
error.Number,
error.Class,
error.State);
}
if (!string.IsNullOrEmpty(detailedMessage) && !isSuppressProviderMessageHeaders)
{
detailedMessage = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", error.Source, detailedMessage);
}
return detailedMessage;
}
/// <summary>
/// Handles a Sql exception
/// </summary>
/// <param name="ex"></param>
/// <returns></returns>
private ScriptExecutionResult HandleSqlException(SqlException ex)
{
ScriptExecutionResult result;
lock (this)
{
if (state == BatchState.Cancelling)
{
result = ScriptExecutionResult.Cancel;
}
else
{
result = ScriptExecutionResult.Failure;
}
}
if (result != ScriptExecutionResult.Cancel)
{
HandleSqlMessages(ex.Errors);
}
return result;
}
/// <summary>
/// Called when an error message came from SqlClient
/// </summary>
/// <param name="message"></param>
/// <param name="description"></param>
/// <param name="line"></param>
/// <param name="textSpan"></param>
private void RaiseBatchError(string message, SqlError error, TextSpan textSpan)
{
BatchErrorEventArgs args = new BatchErrorEventArgs(message, error, textSpan, null);
RaiseBatchError(args);
}
/// <summary>
/// Called when an error message came from SqlClient
/// </summary>
/// <param name="e"></param>
private void RaiseBatchError(BatchErrorEventArgs e)
{
EventHandler<BatchErrorEventArgs> cache = BatchError;
if (cache != null)
{
cache(this, e);
}
}
/// <summary>
/// Called when a message came from SqlClient
/// </summary>
/// <remarks>
/// Additionally, it's being used to notify the user that the script execution
/// has been finished.
/// </remarks>
/// <param name="detailedMessage"></param>
/// <param name="message"></param>
private void RaiseBatchMessage(string detailedMessage, string message, SqlError error)
{
EventHandler<BatchMessageEventArgs> cache = BatchMessage;
if (cache != null)
{
BatchMessageEventArgs args = new BatchMessageEventArgs(detailedMessage, message, error);
cache(this, args);
}
}
/// <summary>
/// Called when a new result set has to be processed
/// </summary>
/// <param name="resultSet"></param>
private void RaiseBatchResultSetProcessing(IDataReader dataReader, ShowPlanType expectedShowPlan)
{
EventHandler<BatchResultSetEventArgs> cache = BatchResultSetProcessing;
if (cache != null)
{
BatchResultSetEventArgs args = new BatchResultSetEventArgs(dataReader, expectedShowPlan);
BatchResultSetProcessing(this, args);
}
}
/// <summary>
/// Called when the result set has been processed
/// </summary>
private void RaiseBatchResultSetFinished()
{
EventHandler<EventArgs> cache = BatchResultSetFinished;
if (cache != null)
{
cache(this, EventArgs.Empty);
}
}
/// <summary>
/// Called when the batch is being cancelled with an active result set
/// </summary>
private void RaiseCancelling()
{
EventHandler<EventArgs> cache = BatchCancelling;
if (cache != null)
{
cache(this, EventArgs.Empty);
}
}
#endregion
#region Private enums
private enum BatchState
{
Initial,
Executing,
Executed,
ProcessingResults,
Cancelling,
}
#endregion
#region Private fields
// correspond to public properties
private bool isSuppressProviderMessageHeaders;
private bool isResultExpected = false;
private string sqlText = string.Empty;
private int execTimeout = 30;
private int scriptTrackingId = 0;
private bool isScriptExecutionTracked = false;
private const int ChangeDatabase = 0x1645;
//command that will be used for execution
private IDbCommand command = null;
//current object state
private BatchState state = BatchState.Initial;
//script text to be executed
private TextSpan textSpan;
//index of the batch in collection of batches
private int index = 0;
private long totalAffectedRows = 0;
private bool hasErrors;
// Expected showplan if any
private ShowPlanType expectedShowPlan;
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public Batch()
{
// nothing
}
/// <summary>
/// Creates and initializes a batch object
/// </summary>
/// <param name="isResultExpected">Whether it is one of "set [something] on/off" type of command,
/// that doesn't return any results from the server
/// </param>
/// <param name="sqlText">Text of the batch</param>
/// <param name="execTimeout">Timeout for the batch execution. 0 means no limit </param>
public Batch(string sqlText, bool isResultExpected, int execTimeout)
{
this.isResultExpected = isResultExpected;
this.sqlText = sqlText;
this.execTimeout = execTimeout;
}
#endregion
#region Public properties
/// <summary>
/// Is the Batch's text valid?
/// </summary>
public bool HasValidText
{
get
{
return !string.IsNullOrEmpty(sqlText);
}
}
/// <summary>
/// SQL text that to be executed in the Batch
/// </summary>
public string Text
{
get
{
return sqlText;
}
set
{
sqlText = value;
}
}
/// <summary>
/// Determines whether batch execution returns any results
/// </summary>
public bool IsResultsExpected
{
get
{
return isResultExpected;
}
set
{
isResultExpected = value;
}
}
/// <summary>
/// Determines the execution timeout for the batch
/// </summary>
public int ExecutionTimeout
{
get
{
return execTimeout;
}
set
{
execTimeout = value;
}
}
/// <summary>
/// Determines the textspan to wich the batch belongs to
/// </summary>
public TextSpan TextSpan
{
get
{
return textSpan;
}
set
{
textSpan = value;
}
}
/// <summary>
/// Determines the batch index in the collection of batches being executed
/// </summary>
public int BatchIndex
{
get
{
return index;
}
set
{
index = value;
}
}
/// <summary>
/// Returns how many rows were affected. It should be the value that can be shown
/// in the UI.
/// </summary>
/// <remarks>
/// It can be used only after the execution of the batch is finished
/// </remarks>
public long RowsAffected
{
get
{
return totalAffectedRows;
}
}
/// <summary>
/// Determines if the error.Source should be used when messages are written
/// </summary>
public bool IsSuppressProviderMessageHeaders
{
get
{
return isSuppressProviderMessageHeaders;
}
set
{
isSuppressProviderMessageHeaders = value;
}
}
/// <summary>
/// Gets or sets the id of the script we are tracking
/// </summary>
public int ScriptTrackingId
{
get
{
return scriptTrackingId;
}
set
{
scriptTrackingId = value;
}
}
#endregion
#region Public events
/// <summary>
/// fired when there is an error message from the server
/// </summary>
public event EventHandler<BatchErrorEventArgs> BatchError = null;
/// <summary>
/// fired when there is a message from the server
/// </summary>
public event EventHandler<BatchMessageEventArgs> BatchMessage = null;
/// <summary>
/// fired when there is a new result set available. It is guarnteed
/// to be fired from the same thread that called Execute method
/// </summary>
public event EventHandler<BatchResultSetEventArgs> BatchResultSetProcessing = null;
/// <summary>
/// fired when the batch recieved cancel request BEFORE it
/// initiates cancel operation. Note that it is fired from a
/// different thread then the one used to kick off execution
/// </summary>
public event EventHandler<EventArgs> BatchCancelling = null;
/// <summary>
/// fired when we've done absolutely all actions for the current result set
/// </summary>
public event EventHandler<EventArgs> BatchResultSetFinished = null;
#endregion
#region Public methods
/// <summary>
/// Resets the object to its initial state
/// </summary>
public void Reset()
{
lock (this)
{
state = BatchState.Initial;
command = null;
textSpan = new TextSpan();
totalAffectedRows = 0;
hasErrors = false;
expectedShowPlan = ShowPlanType.None;
isSuppressProviderMessageHeaders = false;
scriptTrackingId = 0;
isScriptExecutionTracked = false;
}
}
/// <summary>
/// Executes the batch
/// </summary>
/// <param name="connection">Connection to use</param>
/// <param name="expectedShowPlan">ShowPlan type to be used</param>
/// <returns>result of execution</returns>
/// <remarks>
/// It does not return until execution is finished
/// We may have received a Cancel request by the time this function is called
/// </remarks>
public ScriptExecutionResult Execute(SqlConnection connection, ShowPlanType expectedShowPlan)
{
// FUTURE CLEANUP: Remove in favor of general signature (IDbConnection) - #920978
return Execute((IDbConnection)connection, expectedShowPlan);
}
/// <summary>
/// Executes the batch
/// </summary>
/// <param name="connection">Connection to use</param>
/// <param name="expectedShowPlan">ShowPlan type to be used</param>
/// <returns>result of execution</returns>
/// <remarks>
/// It does not return until execution is finished
/// We may have received a Cancel request by the time this function is called
/// </remarks>
public ScriptExecutionResult Execute(IDbConnection connection, ShowPlanType expectedShowPlan)
{
Validate.IsNotNull(nameof(connection), connection);
//makes sure that the batch is not in use
lock (this)
{
Debug.Assert(command == null, "SQLCommand is NOT null");
if (command != null)
{
command = null;
}
}
this.expectedShowPlan = expectedShowPlan;
return DoBatchExecutionImpl(connection, sqlText);
}
/// <summary>
/// Cancels the batch
/// </summary>
/// <remarks>
/// When batch is actually cancelled, Execute() will return with the appropiate status
/// </remarks>
public void Cancel()
{
lock (this)
{
if (state != BatchState.Cancelling)
{
state = BatchState.Cancelling;
RaiseCancelling();
if (command != null)
{
try
{
command.Cancel();
Debug.WriteLine("Batch.Cancel: command.Cancel completed");
}
catch (SqlException)
{
// eat it
}
catch (RetryLimitExceededException)
{
// eat it
}
}
}
}
}
#endregion
#region Protected methods
/// <summary>
/// Fires an error message event
/// </summary>
/// <param name="ex">Exception caught</param>
/// <remarks>
/// Non-SQL exception
/// </remarks>
protected void HandleExceptionMessage(Exception ex)
{
BatchErrorEventArgs args = new BatchErrorEventArgs(string.Format(CultureInfo.CurrentCulture, SR.EE_BatchError_Exception, ex.Message), ex);
RaiseBatchError(args);
}
/// <summary>
/// Fires a message event
/// </summary>
/// <param name="errors">SqlClient errors collection</param>
/// <remarks>
/// Sql specific messages.
/// </remarks>
protected void HandleSqlMessages(SqlErrorCollection errors)
{
foreach (SqlError error in errors)
{
if (error.Number == ChangeDatabase)
{
continue;
}
string detailedMessage = FormatSqlErrorMessage(error);
if (error.Class > 10)
{
// expose this event as error
Debug.Assert(detailedMessage.Length != 0);
RaiseBatchError(detailedMessage, error, textSpan);
//at least one error message has been used
hasErrors = true;
}
else
{
RaiseBatchMessage(detailedMessage, error.Message, error);
}
}
}
/// <summary>
/// method that will be passed as delegate to SqlConnection.InfoMessage
/// </summary>
protected void OnSqlInfoMessageCallback(object sender, SqlInfoMessageEventArgs e)
{
HandleSqlMessages(e.Errors);
}
/// <summary>
/// Delegete for SqlCommand.RecordsAffected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>
/// This is exposed as a regular message
/// </remarks>
protected void OnStatementExecutionFinished(object sender, StatementCompletedEventArgs e)
{
string message = string.Format(CultureInfo.CurrentCulture, SR.EE_BatchExecutionInfo_RowsAffected,
e.RecordCount.ToString(System.Globalization.CultureInfo.InvariantCulture));
RaiseBatchMessage(message, message, null);
}
/// <summary>
/// Called on a new ResultSet on the data reader
/// </summary>
/// <param name="dataReader">True if result set consumed, false on a Cancel request</param>
/// <returns></returns>
/// <remarks>
/// The GridStorageResultSet created is owned by the batch consumer. It's only created here.
/// Additionally, when BatchResultSet event handler is called, it won't return until
/// all data is prcessed or the data being processed is terminated (i.e. cancel or error)
/// </remarks>
protected ScriptExecutionResult ProcessResultSet(IDataReader dataReader)
{
if (dataReader == null)
{
throw new ArgumentNullException();
}
Debug.WriteLine("ProcessResultSet: result set has been created");
//initialize result variable that will be set by batch consumer
ScriptExecutionResult scriptExecutionResult = ScriptExecutionResult.Success;
RaiseBatchResultSetProcessing(dataReader, expectedShowPlan);
if (state != BatchState.Cancelling)
{
return scriptExecutionResult;
}
else
{
return ScriptExecutionResult.Cancel;
}
}
// FUTURE CLEANUP: Remove in favor of general signature (IDbConnection) - #920978
protected ScriptExecutionResult DoBatchExecution(SqlConnection connection, string script)
{
return DoBatchExecutionImpl(connection, script);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities"), SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
[SuppressMessage("Microsoft.Usage", "CA2219:DoNotRaiseExceptionsInExceptionClauses")]
private ScriptExecutionResult DoBatchExecutionImpl(IDbConnection connection, string script)
{
Validate.IsNotNull(nameof(connection), connection);
lock (this)
{
if (state == BatchState.Cancelling)
{
state = BatchState.Initial;
return ScriptExecutionResult.Cancel;
}
}
ScriptExecutionResult result = ScriptExecutionResult.Success;
// SqlClient event handlers setup
SqlInfoMessageEventHandler messageHandler = new SqlInfoMessageEventHandler(OnSqlInfoMessageCallback);
StatementCompletedEventHandler statementCompletedHandler = null;
DbConnectionWrapper connectionWrapper = new DbConnectionWrapper(connection);
connectionWrapper.InfoMessage += messageHandler;
IDbCommand command = connection.CreateCommand();
command.CommandText = script;
command.CommandTimeout = execTimeout;
DbCommandWrapper commandWrapper = null;
if (isScriptExecutionTracked && DbCommandWrapper.IsSupportedCommand(command))
{
statementCompletedHandler = new StatementCompletedEventHandler(OnStatementExecutionFinished);
commandWrapper = new DbCommandWrapper(command);
commandWrapper.StatementCompleted += statementCompletedHandler;
}
lock (this)
{
state = BatchState.Executing;
this.command = command;
command = null;
}
try
{
result = this.ExecuteCommand();
}
catch (OutOfMemoryException)
{
throw;
}
catch (SqlException sqlEx)
{
result = HandleSqlException(sqlEx);
}
catch (Exception ex)
{
result = ScriptExecutionResult.Failure;
HandleExceptionMessage(ex);
}
finally
{
if (messageHandler == null)
{
Logger.Write(LogLevel.Error, "Expected handler to be declared");
}
if (null != connectionWrapper)
{
connectionWrapper.InfoMessage -= messageHandler;
}
if (commandWrapper != null)
{
if (statementCompletedHandler == null)
{
Logger.Write(LogLevel.Error, "Expect handler to be declared if we have a command wrapper");
}
commandWrapper.StatementCompleted -= statementCompletedHandler;
}
lock (this)
{
state = BatchState.Initial;
if (command != null)
{
command.Dispose();
command = null;
}
}
}
return result;
}
private ScriptExecutionResult ExecuteCommand()
{
if (command == null)
{
throw new ArgumentNullException("command");
}
return this.ExecuteUnTrackedCommand();
}
private ScriptExecutionResult ExecuteUnTrackedCommand()
{
IDataReader reader = null;
if (!isResultExpected)
{
command.ExecuteNonQuery();
}
else
{
reader = command.ExecuteReader(CommandBehavior.SequentialAccess);
}
return this.CheckStateAndRead(reader);
}
private ScriptExecutionResult CheckStateAndRead(IDataReader reader = null)
{
ScriptExecutionResult result = ScriptExecutionResult.Success;
if (!isResultExpected)
{
lock (this)
{
if (state == BatchState.Cancelling)
{
result = ScriptExecutionResult.Cancel;
}
else
{
result = ScriptExecutionResult.Success;
state = BatchState.Executed;
}
}
}
else
{
lock (this)
{
if (state == BatchState.Cancelling)
{
result = ScriptExecutionResult.Cancel;
}
else
{
state = BatchState.ProcessingResults;
}
}
if (result != ScriptExecutionResult.Cancel)
{
ScriptExecutionResult batchExecutionResult = ScriptExecutionResult.Success;
if (reader != null)
{
bool hasNextResult = false;
do
{
// if there were no results coming from the server, then the FieldCount is 0
if (reader.FieldCount <= 0)
{
hasNextResult = reader.NextResult();
continue;
}
batchExecutionResult = ProcessResultSet(reader);
if (batchExecutionResult != ScriptExecutionResult.Success)
{
result = batchExecutionResult;
break;
}
RaiseBatchResultSetFinished();
hasNextResult = reader.NextResult();
} while (hasNextResult);
}
if (hasErrors)
{
Debug.WriteLine("DoBatchExecution: successfull processed result set, but there were errors shown to the user");
result = ScriptExecutionResult.Failure;
}
if (result != ScriptExecutionResult.Cancel)
{
lock (this)
{
state = BatchState.Executed;
}
}
}
}
if (reader != null)
{
try
{
// reader.Close() doesn't actually close the reader
// so explicitly dispose the reader
reader.Dispose();
reader = null;
}
catch (OutOfMemoryException)
{
throw;
}
catch (SqlException)
{
// nothing
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,65 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
///<summary>
/// Class to get text from the BatchParser and convert them into batches
///</summary>
public class BatchDefinition
{
/// <summary>
/// Constructor method for a BatchDefinition
/// </summary>
public BatchDefinition(string batchText, int startLine, int endLine, int startColumn, int endColumn)
{
BatchText = batchText;
StartLine = startLine;
EndLine = endLine;
StartColumn = startColumn;
EndColumn = endColumn;
}
/// <summary>
/// Get starting line of the BatchDefinition
/// </summary>
public int StartLine
{
get; private set;
}
/// <summary>
/// Get ending line of the BatchDefinition
/// </summary>
public int EndLine
{
get; private set;
}
/// <summary>
/// Get starting column of the BatchDefinition
/// </summary>
public int StartColumn
{
get; private set;
}
/// <summary>
/// Get ending column of the BatchDefinition
/// </summary>
public int EndColumn
{
get; private set;
}
/// <summary>
/// Get batch text assocaited with the BatchDefinition
/// </summary>
public string BatchText
{
get; private set;
}
}
}

View File

@@ -0,0 +1,141 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Data.SqlClient;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Error totalAffectedRows for a Batch
/// </summary>
internal class BatchErrorEventArgs : EventArgs
{
#region Private Fields
private string message = string.Empty;
private string description = string.Empty;
private int line = -1;
private TextSpan textSpan;
private Exception exception;
private SqlError error;
#endregion
#region Constructors / Destructor
/// <summary>
/// Default constructor
/// </summary>
private BatchErrorEventArgs()
{
}
/// <summary>
/// Constructor with message and no description
/// </summary>
internal BatchErrorEventArgs(string message)
: this(message, null)
{
}
/// <summary>
/// Constructor with exception and no description
/// </summary>
internal BatchErrorEventArgs(string message, Exception ex)
: this(message, string.Empty, ex)
{
}
/// <summary>
/// Constructor with message and description
/// </summary>
internal BatchErrorEventArgs(string message, string description, Exception ex)
: this(message, description, -1, new TextSpan(), ex)
{
}
internal BatchErrorEventArgs(string message, SqlError error, TextSpan textSpan, Exception ex)
{
string desc = error != null ? error.Message : null;
if (error.Number == 7202)
{
desc += " " + Environment.NewLine + SR.TroubleshootingAssistanceMessage;
}
int lineNumber = error != null ? error.LineNumber : -1;
Init(message, desc, lineNumber, textSpan, ex);
this.error = error;
}
/// <summary>
/// Constructor with message, description, textspan and line number
/// </summary>
internal BatchErrorEventArgs(string message, string description, int line, TextSpan textSpan, Exception ex)
{
Init(message, description, line, textSpan, ex);
}
private void Init(string message, string description, int line, TextSpan textSpan, Exception ex)
{
this.message = message;
this.description = description;
this.line = line;
this.textSpan = textSpan;
exception = ex;
}
#endregion
#region Public properties
public string Message
{
get
{
return message;
}
}
public string Description
{
get
{
return description;
}
}
public int Line
{
get
{
return line;
}
}
public TextSpan TextSpan
{
get
{
return textSpan;
}
}
public Exception Exception
{
get
{
return exception;
}
}
public SqlError Error
{
get { return error; }
}
#endregion
}
}

View File

@@ -0,0 +1,58 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Data.SqlClient;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Event args for notification about non-error message
/// </summary>
internal class BatchMessageEventArgs : EventArgs
{
private readonly string message = string.Empty;
private readonly string detailedMessage = string.Empty;
private readonly SqlError error;
private BatchMessageEventArgs()
{
}
internal BatchMessageEventArgs(string msg)
: this(string.Empty, msg)
{
}
internal BatchMessageEventArgs(string detailedMsg, string msg) : this(detailedMsg, msg, null)
{
}
internal BatchMessageEventArgs(string detailedMsg, string msg, SqlError error)
{
message = msg;
detailedMessage = detailedMsg;
this.error = error;
}
public string Message
{
get
{
return message;
}
}
public string DetailedMessage
{
get
{
return detailedMessage;
}
}
public SqlError Error { get { return error; } }
}
}

View File

@@ -0,0 +1,161 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Class that parses queries into batches
/// </summary>
internal class BatchParser :
ICommandHandler,
IVariableResolver
{
#region Private fields
protected ScriptMessageDelegate scriptMessageDelegate;
protected ScriptErrorDelegate scriptErrorDelegate;
protected ExecuteDelegate executeDelegate;
protected HaltParserDelegate haltParserDelegate;
private int startingLine = 0;
protected bool variableSubstitutionDisabled = false;
#endregion
#region Public delegates
public delegate void HaltParserDelegate();
public delegate void ScriptMessageDelegate(string message);
public delegate void ScriptErrorDelegate(string message, ScriptMessageType messageType);
public delegate bool ExecuteDelegate(string batchScript, int num, int lineNumber);
#endregion
#region Constructors / Destructor
public BatchParser()
{
}
#endregion
#region Public properties
public ScriptMessageDelegate Message
{
get { return scriptMessageDelegate; }
set { scriptMessageDelegate = value; }
}
public ScriptErrorDelegate ErrorMessage
{
get { return scriptErrorDelegate; }
set { scriptErrorDelegate = value; }
}
public ExecuteDelegate Execute
{
get { return executeDelegate; }
set { executeDelegate = value; }
}
public HaltParserDelegate HaltParser
{
get { return haltParserDelegate; }
set { haltParserDelegate = value; }
}
public int StartingLine
{
get { return startingLine; }
set { startingLine = value; }
}
#endregion
#region ICommandHandler Members
/// <summary>
/// Take approptiate action on the parsed batches
/// </summary>
public BatchParserAction Go(TextBlock batch, int repeatCount)
{
string str;
LineInfo lineInfo;
batch.GetText(!variableSubstitutionDisabled, out str, out lineInfo);
bool executeResult = false;
if (executeDelegate != null)
{
executeResult = executeDelegate(str, repeatCount, lineInfo.GetStreamPositionForOffset(0).Line + startingLine - 1);
}
return executeResult ? BatchParserAction.Continue : BatchParserAction.Abort;
}
#endregion
#region Protected methods
/// <summary>
/// Called when the script parsing has errors/warnings
/// </summary>
/// <param name="message"></param>
/// <param name="messageType"></param>
protected void RaiseScriptError(string message, ScriptMessageType messageType)
{
if (scriptErrorDelegate != null)
{
scriptErrorDelegate(message, messageType);
}
}
/// <summary>
/// Called on parsing info message
/// </summary>
/// <param name="message"></param>
/// <param name="messageType"></param>
protected void RaiseScriptMessage(string message)
{
if (scriptMessageDelegate != null)
{
scriptMessageDelegate(message);
}
}
/// <summary>
/// Called on parsing info message
/// </summary>
/// <param name="message"></param>
/// <param name="messageType"></param>
protected void RaiseHaltParser()
{
if (haltParserDelegate != null)
{
haltParserDelegate();
}
}
#endregion
public virtual BatchParserAction OnError(Token token, OnErrorAction action)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public virtual BatchParserAction Include(TextBlock filename, out System.IO.TextReader stream, out string newFilename)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public virtual string GetVariable(PositionStruct pos, string name)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public virtual void SetVariable(PositionStruct pos, string name, string value)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
internal void DisableVariableSubstitution()
{
variableSubstitutionDisabled = true;
}
}
}

View File

@@ -0,0 +1,33 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Class associated with batch parser execution errors
/// </summary>
internal class BatchParserExecutionErrorEventArgs : BatchErrorEventArgs
{
private readonly ScriptMessageType messageType;
/// <summary>
/// Constructor method for BatchParserExecutionErrorEventArgs class
/// </summary>
public BatchParserExecutionErrorEventArgs(string errorLine, string message, ScriptMessageType messageType)
: base(errorLine, message, null)
{
this.messageType = messageType;
}
public ScriptMessageType MessageType
{
get
{
return messageType;
}
}
}
}

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Class associated with batch parser execution finished event
/// </summary>
internal class BatchParserExecutionFinishedEventArgs : EventArgs
{
private readonly Batch batch = null;
private readonly ScriptExecutionResult result;
private BatchParserExecutionFinishedEventArgs()
{
}
/// <summary>
/// Constructor method for the class
/// </summary>
public BatchParserExecutionFinishedEventArgs(ScriptExecutionResult batchResult, Batch batch)
{
this.batch = batch;
result = batchResult;
}
public Batch Batch
{
get
{
return batch;
}
}
public ScriptExecutionResult ExecutionResult
{
get
{
return result;
}
}
}
}

View File

@@ -0,0 +1,50 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Class associated with batch parser execution start event
/// </summary>
internal class BatchParserExecutionStartEventArgs : EventArgs
{
private readonly Batch batch = null;
private readonly TextSpan textSpan;
private BatchParserExecutionStartEventArgs()
{
}
/// <summary>
/// Contructor method for the class
/// </summary>
public BatchParserExecutionStartEventArgs(TextSpan textSpan, Batch batch)
{
this.batch = batch;
this.textSpan = textSpan;
}
public Batch Batch
{
get
{
return batch;
}
}
public TextSpan TextSpan
{
get
{
return textSpan;
}
}
}
}

View File

@@ -0,0 +1,133 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.IO;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Class for handling SQL CMD by Batch Parser
/// </summary>
internal class BatchParserSqlCmd : BatchParser
{
/// <summary>
/// The internal variables that can be used in SqlCommand substitution.
/// These variables take precedence over environment variables.
/// </summary>
private Dictionary<string, string> internalVariables = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
private ConnectionChangedDelegate connectionChangedDelegate;
private ErrorActionChangedDelegate errorActionChangedDelegate;
public delegate void ConnectionChangedDelegate(SqlConnectionStringBuilder connectionstringBuilder);
public delegate void ErrorActionChangedDelegate(OnErrorAction ea);
/// <summary>
/// Constructor taking a Parser instance
/// </summary>
/// <param name="parser"></param>
public BatchParserSqlCmd()
: base()
{
// nothing
}
internal ConnectionChangedDelegate ConnectionChanged
{
get { return connectionChangedDelegate; }
set { connectionChangedDelegate = value; }
}
internal ErrorActionChangedDelegate ErrorActionChanged
{
get { return errorActionChangedDelegate; }
set { errorActionChangedDelegate = value; }
}
/// <summary>
/// Looks for any environment variable or internal variable.
/// </summary>
public override string GetVariable(PositionStruct pos, string name)
{
if (variableSubstitutionDisabled)
{
return null;
}
string value;
// Internally defined variables have higher precedence over environment variables.
if (!internalVariables.TryGetValue(name, out value))
{
value = Environment.GetEnvironmentVariables()[name] as string;
}
if (value == null)
{
RaiseScriptError(string.Format(CultureInfo.CurrentCulture, SR.EE_ExecutionError_VariableNotFound, name), ScriptMessageType.FatalError);
RaiseHaltParser();
// TODO: Halt the parser, should get/set variable have ParserAction.Abort/Continue (like original?)
}
return value;
}
/// <summary>
/// Set environment or internal variable
/// </summary>
public override void SetVariable(PositionStruct pos, string name, string value)
{
if (variableSubstitutionDisabled)
{
return;
}
if (value == null)
{
if (internalVariables.ContainsKey(name))
{
internalVariables.Remove(name);
}
}
else
{
internalVariables[name] = value;
}
}
public Dictionary<string, string> InternalVariables
{
get { return internalVariables; }
set { internalVariables = value; }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "ppIBatchSource")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "fileName")]
public override BatchParserAction Include(TextBlock filename, out TextReader stream, out string newFilename)
{
stream = null;
newFilename = null;
RaiseScriptError(string.Format(CultureInfo.CurrentCulture, SR.EE_ExecutionError_CommandNotSupported, "Include"), ScriptMessageType.Error);
return BatchParserAction.Abort;
}
/// <summary>
/// Method to deal with errors
/// </summary>
public override BatchParserAction OnError(Token token, OnErrorAction ea)
{
if (errorActionChangedDelegate != null)
{
errorActionChangedDelegate(ea);
}
return BatchParserAction.Continue;
}
}
}

View File

@@ -0,0 +1,52 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Data;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
/// <summary>
/// Class associated with setting batch results
/// </summary>
internal class BatchResultSetEventArgs : EventArgs
{
private readonly IDataReader dataReader = null;
private readonly ShowPlanType expectedShowPlan = ShowPlanType.None;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="dataReader"></param>
internal BatchResultSetEventArgs(IDataReader dataReader, ShowPlanType expectedShowPlan)
{
this.dataReader = dataReader;
this.expectedShowPlan = expectedShowPlan;
}
/// <summary>
/// Data reader associated with the result set
/// </summary>
public IDataReader DataReader
{
get
{
return dataReader;
}
}
/// <summary>
/// Show Plan to be expected if any during the execution
/// </summary>
public ShowPlanType ExpectedShowPlan
{
get
{
return expectedShowPlan;
}
}
}
}

View File

@@ -0,0 +1,277 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Specialized;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal class ExecutionEngineConditions
{
#region Private fields
private static class Consts
{
public static string On = "ON";
public static string Off = "OFF";
public static string ParseOnly = "SET PARSEONLY {0}";
public static string NoExec = "SET NOEXEC {0}";
public static string StatisticsIO = "SET STATISTICS IO {0}";
public static string StatisticsTime = "SET STATISTICS TIME {0}";
public static string ShowPlanXml = "SET SHOWPLAN_XML {0}";
public static string ShowPlanAll = "SET SHOWPLAN_ALL {0}";
public static string ShowPlanText = "SET SHOWPLAN_TEXT {0}";
public static string StatisticsXml = "SET STATISTICS XML {0}";
public static string StatisticsProfile = "SET STATISTICS PROFILE {0}";
public static string BeginTrans = "BEGIN TRAN";
public static string CommitTrans = "COMMIT TRAN";
public static string Rollback = "ROLLBACK";
public static string BatchSeparator = "GO";
public static string Reset = "SET NOEXEC, FMTONLY OFF, PARSEONLY, SET SHOWPLAN_ALL, SET SHOWPLAN_TEXT";
}
private static readonly int stateParseOnly = BitVector32.CreateMask();
private static readonly int stateTransactionWrapped = BitVector32.CreateMask(stateParseOnly);
private static readonly int stateHaltOnError = BitVector32.CreateMask(stateTransactionWrapped);
private static readonly int stateEstimatedShowPlan = BitVector32.CreateMask(stateHaltOnError);
private static readonly int stateActualShowPlan = BitVector32.CreateMask(stateEstimatedShowPlan);
private static readonly int stateSuppressProviderMessageHeaders = BitVector32.CreateMask(stateActualShowPlan);
private static readonly int stateNoExec = BitVector32.CreateMask(stateSuppressProviderMessageHeaders);
private static readonly int stateStatisticsIO = BitVector32.CreateMask(stateNoExec);
private static readonly int stateShowPlanText = BitVector32.CreateMask(stateStatisticsIO);
private static readonly int stateStatisticsTime = BitVector32.CreateMask(stateShowPlanText);
private static readonly int stateSqlCmd = BitVector32.CreateMask(stateStatisticsTime);
private static readonly int stateScriptExecutionTracked = BitVector32.CreateMask(stateSqlCmd);
private BitVector32 state = new BitVector32();
private string batchSeparator = Consts.BatchSeparator;
#endregion
#region Constructors / Destructor
/// <summary>
/// Default constructor
/// </summary>
public ExecutionEngineConditions()
{
// nothing
}
/// <summary>
/// Overloaded constructor taking another ExecutionEngineCondition object as a reference
/// </summary>
public ExecutionEngineConditions(ExecutionEngineConditions condition)
{
state = condition.state;
batchSeparator = condition.batchSeparator;
}
#endregion
#region Statement strings
public static string ShowPlanXmlStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.ShowPlanXml, (isOn ? Consts.On : Consts.Off));
}
public static string ShowPlanAllStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.ShowPlanAll, (isOn ? Consts.On : Consts.Off));
}
public static string ShowPlanTextStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.ShowPlanText, (isOn ? Consts.On : Consts.Off));
}
public static string StatisticsXmlStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.StatisticsXml, (isOn ? Consts.On : Consts.Off));
}
public static string StatisticsProfileStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.StatisticsProfile, (isOn ? Consts.On : Consts.Off));
}
public static string ParseOnlyStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.ParseOnly, (isOn ? Consts.On : Consts.Off));
}
public static string NoExecStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.NoExec, (isOn ? Consts.On : Consts.Off));
}
public static string StatisticsIOStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.StatisticsIO, (isOn ? Consts.On : Consts.Off));
}
public static string StatisticsTimeStatement(bool isOn)
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture, Consts.StatisticsTime, (isOn ? Consts.On : Consts.Off));
}
public static string BeginTransactionStatement
{
get { return Consts.BeginTrans; }
}
public static string CommitTransactionStatement
{
get { return Consts.CommitTrans; }
}
public static string RollbackTransactionStatement
{
get { return Consts.Rollback; }
}
public static string BatchSeparatorStatement
{
get { return Consts.BatchSeparator; }
}
public static string ResetStatement
{
get { return Consts.Reset; }
}
#endregion
#region Public properties
/// <summary>
/// Checks the syntax of each Transact-SQL statement and returns any error messages
/// without compiling or executing the statement.
/// </summary>
public bool IsParseOnly
{
get { return state[stateParseOnly]; }
set { state[stateParseOnly] = value; }
}
/// <summary>
/// Script is wrapped withint BEGIN TRAN/COMMIT-ROLLBACK
/// </summary>
public bool IsTransactionWrapped
{
get { return state[stateTransactionWrapped]; }
set { state[stateTransactionWrapped] = value; }
}
/// <summary>
/// Gets or a set a value indicating whether script execution is tracked
/// </summary>
public bool IsScriptExecutionTracked
{
get { return state[stateScriptExecutionTracked]; }
set { state[stateScriptExecutionTracked] = value; }
}
/// <summary>
/// Halts the execution if an error is found
/// </summary>
public bool IsHaltOnError
{
get { return state[stateHaltOnError]; }
set { state[stateHaltOnError] = value; }
}
/// <summary>
/// Use estimated show plan
/// </summary>
public bool IsEstimatedShowPlan
{
get { return state[stateEstimatedShowPlan]; }
set { state[stateEstimatedShowPlan] = value; }
}
/// <summary>
/// Use actual show plan
/// </summary>
public bool IsActualShowPlan
{
get { return state[stateActualShowPlan]; }
set { state[stateActualShowPlan] = value; }
}
/// <summary>
/// Use Source information on messages shown to the user
/// </summary>
public bool IsSuppressProviderMessageHeaders
{
get { return state[stateSuppressProviderMessageHeaders]; }
set { state[stateSuppressProviderMessageHeaders] = value; }
}
/// <summary>
/// SET NO EXEC {on/off}
/// </summary>
public bool IsNoExec
{
get { return state[stateNoExec]; }
set { state[stateNoExec] = value; }
}
/// <summary>
/// SET STATISTICS IO {on/off}
/// </summary>
public bool IsStatisticsIO
{
get { return state[stateStatisticsIO]; }
set { state[stateStatisticsIO] = value; }
}
/// <summary>
/// SET SHOWPLAN_TEXT {on/off}
/// </summary>
public bool IsShowPlanText
{
get { return state[stateShowPlanText]; }
set { state[stateShowPlanText] = value; }
}
/// <summary>
/// SET STATISTICS IO {on/off}
/// </summary>
public bool IsStatisticsTime
{
get { return state[stateStatisticsTime]; }
set { state[stateStatisticsTime] = value; }
}
/// <summary>
/// SqlCmd support
/// </summary>
public bool IsSqlCmd
{
get { return state[stateSqlCmd]; }
set { state[stateSqlCmd] = value; }
}
/// <summary>
/// Batch separator statement
/// </summary>
public string BatchSeparator
{
get
{
return batchSeparator;
}
set
{
Validate.IsNotNullOrEmptyString(nameof(value), value);
batchSeparator = value;
}
}
#endregion
}
}

View File

@@ -0,0 +1,16 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal enum ExecutionState
{
Initial,
Executing,
ExecutingBatch,
Cancelling,
Discarded
}
}

View File

@@ -0,0 +1,40 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal interface IBatchEventsHandler
{
/// <summary>
/// fired when there is an error message from the server
/// </summary>
void OnBatchError(object sender, BatchErrorEventArgs args);
/// <summary>
/// fired when there is a message from the server
/// </summary>
void OnBatchMessage(object sender, BatchMessageEventArgs args);
/// <summary>
/// fired when there is a new result set available. It is guarnteed
/// to be fired from the same thread that called Execute method
/// </summary>
void OnBatchResultSetProcessing(object sender, BatchResultSetEventArgs args);
/// <summary>
/// fired when we've done absolutely all actions for the current result set
/// </summary>
void OnBatchResultSetFinished(object sender, EventArgs args);
/// <summary>
/// fired when the batch recieved cancel request BEFORE it
/// initiates cancel operation. Note that it is fired from a
/// different thread then the one used to kick off execution
/// </summary>
void OnBatchCancelling(object sender, EventArgs args);
}
}

View File

@@ -0,0 +1,143 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal class ScriptExecutionArgs : EventArgs
{
private IDbConnection connection;
private IBatchEventsHandler batchEventHandlers;
private int startingLine;
private Dictionary<string, string> cmdVariables;
#region Constructors / Destructor
/// <summary>
/// Constructor method for ScriptExecutionArgs
/// </summary>
public ScriptExecutionArgs(
string script,
SqlConnection connection,
int timeOut,
ExecutionEngineConditions conditions,
IBatchEventsHandler batchEventHandlers)
: this (script, (IDbConnection)connection, timeOut, conditions, batchEventHandlers)
{
// nothing
}
/// <summary>
/// Constructor method for ScriptExecutionArgs
/// </summary>
public ScriptExecutionArgs(
string script,
SqlConnection connection,
int timeOut,
ExecutionEngineConditions conditions,
IBatchEventsHandler batchEventHandlers,
int startingLine,
IDictionary<string,string> variables)
: this(script, (IDbConnection) connection, timeOut, conditions, batchEventHandlers, startingLine, variables)
{
// nothing
}
/// <summary>
/// Constructor method for ScriptExecutionArgs
/// </summary>
public ScriptExecutionArgs(
string script,
IDbConnection connection,
int timeOut,
ExecutionEngineConditions conditions,
IBatchEventsHandler batchEventHandlers)
: this(script, connection, timeOut, conditions, batchEventHandlers, 0, null)
{
// nothing
}
/// <summary>
/// Constructor method for ScriptExecutionArgs
/// </summary>
public ScriptExecutionArgs(
string script,
IDbConnection connection,
int timeOut,
ExecutionEngineConditions conditions,
IBatchEventsHandler batchEventHandlers,
int startingLine,
IDictionary<string, string> variables)
{
Script = script;
this.connection = connection;
TimeOut = timeOut;
Conditions = conditions;
this.batchEventHandlers = batchEventHandlers;
this.startingLine = startingLine;
if (variables != null)
{
foreach (var variable in variables)
{
Variables[variable.Key] = variable.Value;
}
}
}
#endregion
#region Public properties
public string Script { get; set; }
// FUTURE CLEANUP: Remove in favor of general signature (IDbConnection) - #920978
public SqlConnection Connection
{
get { return connection as SqlConnection; }
set { connection = value as SqlConnection; }
}
public IDbConnection ReliableConnection
{
get { return connection; }
set { connection = value; }
}
public int TimeOut { get; set; }
internal ExecutionEngineConditions Conditions { get; set; }
internal IBatchEventsHandler BatchEventHandlers
{
get { return batchEventHandlers; }
set { batchEventHandlers = value; }
}
internal int StartingLine
{
get { return startingLine; }
set { startingLine = value; }
}
internal Dictionary<string, string> Variables
{
get
{
if (cmdVariables == null)
{
cmdVariables = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
}
return cmdVariables;
}
}
#endregion
}
}

View File

@@ -0,0 +1,29 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal class ScriptExecutionFinishedEventArgs : EventArgs
{
internal ScriptExecutionFinishedEventArgs(ScriptExecutionResult result)
{
ExecutionResult = result;
}
public ScriptExecutionResult ExecutionResult
{
private set;
get;
}
public bool Disposing
{
get;
set;
}
}
}

View File

@@ -0,0 +1,20 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
[Flags]
internal enum ScriptExecutionResult
{
Success = 0x1,
Failure = 0x2,
Cancel = 0x4,
Halted = 0x8,
All = 0x0F
}
}

View File

@@ -0,0 +1,14 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal enum ScriptMessageType
{
FatalError,
Error,
Warning
}
}

View File

@@ -0,0 +1,20 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
[System.Flags]
internal enum ShowPlanType
{
None = 0x0,
ActualExecutionShowPlan = 0x1,
ActualXmlShowPlan = 0x2,
EstimatedExecutionShowPlan = 0x4,
EstimatedXmlShowPlan = 0x8,
AllXmlShowPlan = ActualXmlShowPlan | EstimatedXmlShowPlan,
AllExecutionShowPlan = ActualExecutionShowPlan | EstimatedExecutionShowPlan,
AllShowPlan = AllExecutionShowPlan | AllXmlShowPlan
}
}

View File

@@ -0,0 +1,15 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
internal struct TextSpan
{
public int iEndIndex;
public int iEndLine;
public int iStartIndex;
public int iStartLine;
}
}