//
// 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 Microsoft.Data.SqlClient;
using System.Globalization;
using System.IO;
using Microsoft.SqlTools.ManagedBatchParser;
namespace Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode
{
///
/// Class for handling SQL CMD by Batch Parser
///
public class BatchParserSqlCmd : BatchParser
{
///
/// The internal variables that can be used in SqlCommand substitution.
/// These variables take precedence over environment variables.
///
private Dictionary internalVariables = new Dictionary(StringComparer.CurrentCultureIgnoreCase);
private ConnectionChangedDelegate connectionChangedDelegate;
private ErrorActionChangedDelegate errorActionChangedDelegate;
public delegate void ConnectionChangedDelegate(SqlConnectionStringBuilder connectionstringBuilder);
public delegate void ErrorActionChangedDelegate(OnErrorAction ea);
///
/// Constructor taking a Parser instance
///
///
public BatchParserSqlCmd()
: base()
{
// nothing
}
public ConnectionChangedDelegate ConnectionChanged
{
get { return connectionChangedDelegate; }
set { connectionChangedDelegate = value; }
}
public ErrorActionChangedDelegate ErrorActionChanged
{
get { return errorActionChangedDelegate; }
set { errorActionChangedDelegate = value; }
}
///
/// Looks for any environment variable or internal variable.
///
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;
}
///
/// Set environment or internal variable
///
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 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;
LineInfo lineInfo;
if (filename == null)
{
stream = null;
return BatchParserAction.Abort;
}
filename.GetText(resolveVariables: true, text: out newFilename, lineInfo: out lineInfo);
string resolvedFileNameWithFullPath = GetFilePath(newFilename);
if (!File.Exists(resolvedFileNameWithFullPath))
{
stream = null;
return BatchParserAction.Abort;
}
else
{
stream = new StreamReader(resolvedFileNameWithFullPath);
}
return BatchParserAction.Continue;
}
private string GetFilePath(string fileName)
{
//try appending the file name with current working directory path
string fullFileName = null;
try
{
if (Environment.CurrentDirectory != null && !File.Exists(fileName))
{
string currentWorkingDirectory = Environment.CurrentDirectory;
if (currentWorkingDirectory != null)
{
fullFileName = Path.GetFullPath(Path.Combine(currentWorkingDirectory, fileName));
if (!File.Exists(fullFileName))
{
fullFileName = null;
}
}
}
if (fullFileName == null)
{
fullFileName = Path.GetFullPath(fileName);
}
return fullFileName;
}
catch (ArgumentException)
{
//path contains invalid path characters.
throw new SqlCmdException(SR.SqlCmd_PathInvalid);
}
catch (PathTooLongException)
{
//path is too long
throw new SqlCmdException(SR.SqlCmd_PathLong);
}
catch (Exception)
{
//catch all other exceptions and report generic error
throw new SqlCmdException(string.Format(SR.SqlCmd_FailedInclude, fileName));
}
}
///
/// Method to deal with errors
///
public override BatchParserAction OnError(Token token, OnErrorAction ea)
{
if (errorActionChangedDelegate != null)
{
errorActionChangedDelegate(ea);
}
return BatchParserAction.Continue;
}
}
}