mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-30 01:25:45 -05:00
Move managed parser into its own project (test code coverage) (#774)
* Created New ManagedBatchParser project in .NetStandard * Addressing PR Comments * Resolve 'No Repository' warning. * Move batch parser tests to integrations test project * Fix SLN file
This commit is contained in:
@@ -0,0 +1,892 @@
|
||||
//
|
||||
// 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.Utility;
|
||||
using Microsoft.SqlTools.ManagedBatchParser;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Single batch of SQL command
|
||||
/// </summary>
|
||||
public 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 int expectedExecutionCount = 1;
|
||||
|
||||
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>
|
||||
/// The number of times this batch is expected to be executed. Will be 1 by default, but for statements
|
||||
/// with "GO 2" or other numerical values, will have a number > 1
|
||||
/// </summary>
|
||||
public int ExpectedExecutionCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return expectedExecutionCount;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
expectedExecutionCount = 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(TraceEventType.Error, "Expected handler to be declared");
|
||||
}
|
||||
|
||||
if (null != connectionWrapper)
|
||||
{
|
||||
connectionWrapper.InfoMessage -= messageHandler;
|
||||
}
|
||||
|
||||
if (commandWrapper != null)
|
||||
{
|
||||
|
||||
if (statementCompletedHandler == null)
|
||||
{
|
||||
Logger.Write(TraceEventType.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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// 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, int executionCount)
|
||||
{
|
||||
BatchText = batchText;
|
||||
StartLine = startLine;
|
||||
EndLine = endLine;
|
||||
StartColumn = startColumn;
|
||||
EndColumn = endColumn;
|
||||
// set the batch execution count, with min value of 1
|
||||
BatchExecutionCount = executionCount > 0 ? executionCount : 1;
|
||||
}
|
||||
|
||||
/// <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 associated with the BatchDefinition
|
||||
/// </summary>
|
||||
public string BatchText
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get number of times to execute this batch
|
||||
/// </summary>
|
||||
public int BatchExecutionCount
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// 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;
|
||||
using Microsoft.SqlTools.ManagedBatchParser;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Error totalAffectedRows for a Batch
|
||||
/// </summary>
|
||||
public 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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
public 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; } }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
public 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.");
|
||||
}
|
||||
|
||||
public void DisableVariableSubstitution()
|
||||
{
|
||||
variableSubstitutionDisabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// 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;
|
||||
using Microsoft.SqlTools.ManagedBatchParser;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for handling SQL CMD by Batch Parser
|
||||
/// </summary>
|
||||
public 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
|
||||
}
|
||||
|
||||
public ConnectionChangedDelegate ConnectionChanged
|
||||
{
|
||||
get { return connectionChangedDelegate; }
|
||||
set { connectionChangedDelegate = value; }
|
||||
}
|
||||
|
||||
public 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
|
||||
{
|
||||
public 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
public 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
public class ScriptExecutionFinishedEventArgs : EventArgs
|
||||
{
|
||||
internal ScriptExecutionFinishedEventArgs(ScriptExecutionResult result)
|
||||
{
|
||||
ExecutionResult = result;
|
||||
}
|
||||
|
||||
public ScriptExecutionResult ExecutionResult
|
||||
{
|
||||
private set;
|
||||
get;
|
||||
}
|
||||
|
||||
public bool Disposing
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
public enum ScriptExecutionResult
|
||||
{
|
||||
Success = 0x1,
|
||||
Failure = 0x2,
|
||||
Cancel = 0x4,
|
||||
Halted = 0x8,
|
||||
All = 0x0F
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
public enum ScriptMessageType
|
||||
{
|
||||
FatalError,
|
||||
Error,
|
||||
Warning
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
public enum ShowPlanType
|
||||
{
|
||||
None = 0x0,
|
||||
ActualExecutionShowPlan = 0x1,
|
||||
ActualXmlShowPlan = 0x2,
|
||||
EstimatedExecutionShowPlan = 0x4,
|
||||
EstimatedXmlShowPlan = 0x8,
|
||||
AllXmlShowPlan = ActualXmlShowPlan | EstimatedXmlShowPlan,
|
||||
AllExecutionShowPlan = ActualExecutionShowPlan | EstimatedExecutionShowPlan,
|
||||
AllShowPlan = AllExecutionShowPlan | AllXmlShowPlan
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
public struct TextSpan
|
||||
{
|
||||
public int iEndIndex;
|
||||
public int iEndLine;
|
||||
public int iStartIndex;
|
||||
public int iStartLine;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user