Add Agent Job and Job Step request handlers (#635)

* Stage changes

* Fix update job request handler

* WIP

* Additional agent handler updates

* Setup agent job step create test

* Fix Step update handler
This commit is contained in:
Karl Burtram
2018-06-13 10:02:25 -07:00
committed by GitHub
parent 7c1f78a678
commit 8dda34c95a
52 changed files with 705 additions and 619 deletions

View File

@@ -7,12 +7,13 @@ using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlServer.Management.Smo;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
@@ -189,51 +190,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
}
/// <summary>
/// Create a data container object
/// </summary>
/// <param name="connInfo">connection info</param>
/// <param name="databaseExists">flag indicating whether to create taskhelper for existing database or not</param>
internal static CDataContainer CreateDataContainer(ConnectionInfo connInfo, bool databaseExists = false)
{
XmlDocument xmlDoc = CreateDataContainerDocument(connInfo, databaseExists);
CDataContainer dataContainer;
// add alternate port to server name property if provided
var connectionDetails = connInfo.ConnectionDetails;
string serverName = !connectionDetails.Port.HasValue
? connectionDetails.ServerName
: string.Format("{0},{1}", connectionDetails.ServerName, connectionDetails.Port.Value);
// check if the connection is using SQL Auth or Integrated Auth
//TODO: ConnectionQueue try to get an existing connection (ConnectionQueue)
if (string.Equals(connectionDetails.AuthenticationType, "SqlLogin", StringComparison.OrdinalIgnoreCase))
{
var passwordSecureString = BuildSecureStringFromPassword(connectionDetails.Password);
dataContainer = new CDataContainer(
CDataContainer.ServerType.SQL,
serverName,
false,
connectionDetails.UserName,
passwordSecureString,
connectionDetails.DatabaseName,
xmlDoc.InnerXml);
}
else
{
dataContainer = new CDataContainer(
CDataContainer.ServerType.SQL,
serverName,
true,
null,
null,
connectionDetails.DatabaseName,
xmlDoc.InnerXml);
}
return dataContainer;
}
/// <summary>
/// Create database task helper
/// </summary>
@@ -242,65 +198,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <returns></returns>
internal static DatabaseTaskHelper CreateDatabaseTaskHelper(ConnectionInfo connInfo, bool databaseExists = false)
{
var dataContainer = CreateDataContainer(connInfo, databaseExists);
var dataContainer = CDataContainer.CreateDataContainer(connInfo, databaseExists);
var taskHelper = new DatabaseTaskHelper(dataContainer);
return taskHelper;
}
internal static System.Security.SecureString BuildSecureStringFromPassword(string password) {
var passwordSecureString = new System.Security.SecureString();
if (password != null) {
foreach (char c in password) {
passwordSecureString.AppendChar(c);
}
}
return passwordSecureString;
}
/// <summary>
/// Create data container document
/// </summary>
/// <param name="connInfo">connection info</param>
/// <param name="databaseExists">flag indicating whether to create document for existing database or not</param>
/// <returns></returns>
private static XmlDocument CreateDataContainerDocument(ConnectionInfo connInfo, bool databaseExists)
{
string xml = string.Empty;
if (!databaseExists)
{
xml =
string.Format(@"<?xml version=""1.0""?>
<formdescription><params>
<servername>{0}</servername>
<connectionmoniker>{0} (SQLServer, user = {1})</connectionmoniker>
<servertype>sql</servertype>
<urn>Server[@Name='{0}']</urn>
<itemtype>Database</itemtype>
</params></formdescription> ",
connInfo.ConnectionDetails.ServerName.ToUpper(),
connInfo.ConnectionDetails.UserName);
}
else
{
xml =
string.Format(@"<?xml version=""1.0""?>
<formdescription><params>
<servername>{0}</servername>
<connectionmoniker>{0} (SQLServer, user = {1})</connectionmoniker>
<servertype>sql</servertype>
<urn>Server[@Name='{0}']</urn>
<database>{2}</database>
</params></formdescription> ",
connInfo.ConnectionDetails.ServerName.ToUpper(),
connInfo.ConnectionDetails.UserName,
connInfo.ConnectionDetails.DatabaseName);
}
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
return xmlDoc;
}
/// <summary>
/// Handles a create login request
/// </summary>

View File

@@ -1,87 +0,0 @@
//
// 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.Text;
using System.IO;
using System.Data;
using System.Text.RegularExpressions;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Diagnostics;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Helper static class for the BrowseFolder dialog
/// </summary>
internal static class BrowseFolderHelper
{
/// <summary>
/// Get the initial directory for the browse folder dialog
/// </summary>
/// <param name="serverConnection">The connection to the server</param>
/// <returns></returns>
public static string GetBrowseStartPath(ServerConnection serverConnection)
{
string result = String.Empty;
// if (US.Current.SSMS.TaskForms.ServerFileSystem.LastPath.TryGetValue(serverConnection.TrueName, out result))
// {
// return result;
// }
if ((result == null) || (result.Length == 0))
{
// try and fetch the default location from SMO...
Microsoft.SqlServer.Management.Smo.Server server = new Microsoft.SqlServer.Management.Smo.Server(serverConnection);
result = server.Settings.DefaultFile;
if ((result == null) || (result.Length == 0))
{
// if the default file property doesn't return a string,
// use the location of the model database's data file.
Enumerator enumerator = new Enumerator();
Request request = new Request();
request.Urn = "Server/Database[@Name='model']/FileGroup[@Name='PRIMARY']/File";
request.Fields = new string[1] {"FileName"};
DataSet dataSet = enumerator.Process(serverConnection, request);
if (0 < dataSet.Tables[0].Rows.Count)
{
string path = dataSet.Tables[0].Rows[0][0].ToString();
result = PathWrapper.GetDirectoryName(path);
}
}
}
return result;
}
}
/// <summary>
/// Static class with Utility functions dealing with filenames
/// </summary>
internal static class FileNameHelper
{
/// <summary>
/// Checks whether a filename has invalid characters
/// </summary>
/// <param name="testName">filename to check</param>
/// <returns>true if filename has only valid characters</returns>
internal static bool IsValidFilename(string testName)
{
bool isValid = false;
if (!string.IsNullOrEmpty(testName))
{
Regex containsBadCharacter = new Regex("[" + Regex.Escape(new String(Path.GetInvalidFileNameChars())) + "]");
isValid = !containsBadCharacter.IsMatch(testName);
}
return isValid;
}
}
}

View File

@@ -1,173 +0,0 @@
//
// 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.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Common;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Helper class to describe the size of an Azure database
/// </summary>
public class DbSize
{
public enum SizeUnits
{
MB,
GB,
TB
}
#region Member Vars
private readonly int size;
private readonly SizeUnits sizeUnit;
#endregion
public DbSize(int size, SizeUnits sizeUnit)
{
this.size = size;
this.sizeUnit = sizeUnit;
}
/// <summary>
/// Copy constructor
/// </summary>
public DbSize(DbSize copy)
{
this.size = copy.Size;
this.sizeUnit = copy.SizeUnit;
}
/// <summary>
/// Size of the DB
/// </summary>
public int Size
{
get
{
return size;
}
}
/// <summary>
/// Units that the size is measured in
/// </summary>
public SizeUnits SizeUnit
{
get
{
return sizeUnit;
}
}
/// <summary>
/// Returns the number of bytes represented by the DbSize
/// </summary>
public double SizeInBytes
{
get
{
var sizeBase = Convert.ToDouble(this.size);
switch (SizeUnit)
{
case SizeUnits.MB:
return sizeBase*1024.0*1024.0;
case SizeUnits.GB:
return sizeBase*1024.0*1024.0*1024.0;
case SizeUnits.TB:
return sizeBase*1024.0*1024.0*1024.0*1024.0;
}
throw new InvalidOperationException("SR.UnknownSizeUnit(SizeUnit.ToString())");
}
}
#region Object Overrides
/// <summary>
/// Displays the size in the format ####UU (e.g. 100GB)
/// </summary>
/// <returns></returns>
public override string ToString()
{
return size + sizeUnit.ToString();
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return this == (DbSize)obj;
}
public override int GetHashCode()
{
return this.size.GetHashCode() ^ this.sizeUnit.GetHashCode();
}
#endregion Object Overrides
/// <summary>
/// Parses a string in the format ####UU into a DbSize object. The number of
/// numeric characters must be parseable into an int and the last two characters
/// mapped to one of the SizeUnits enum values.
/// </summary>
/// <param name="dbSizeString"></param>
/// <returns></returns>
public static DbSize ParseDbSize(string dbSizeString)
{
if (dbSizeString == null || dbSizeString.Length < 3)
{ //Sanity check
throw new ArgumentException("DbSize string must be at least 3 characters (#UU)");
}
int size;
//Try and parse all but the last two characters into the size
if (int.TryParse(dbSizeString.Substring(0, dbSizeString.Length - 2), out size))
{
//Get the unit portion (last two characters)
string unitPortion = dbSizeString.Substring(dbSizeString.Length - 2 );
SizeUnits unit;
if (Enum.TryParse(unitPortion, true, out unit))
{
return new DbSize(size, unit);
}
else
{
throw new ArgumentException("DbSize string does not contain a valid unit portion");
}
}
else
{
throw new ArgumentException("DbSize string does not contain a valid numeric portion");
}
}
public static bool operator ==(DbSize x, DbSize y)
{
if(ReferenceEquals(x, y))
{ //Both null or both same instance, are equal
return true;
}
if((object)x == null || (object)y == null)
{ //Only one null, never equal (cast to object to avoid infinite loop of ==)
return false;
}
return x.size == y.size && x.sizeUnit == y.sizeUnit;
}
public static bool operator !=(DbSize x, DbSize y)
{
return !(x == y);
}
}
}

View File

@@ -1,203 +0,0 @@
//
// 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;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Diagnostics;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Provides connection and enumerator context for a node
/// </summary>
public interface IManagedConnection : IDisposable
{
/// <summary>
/// Connection information.
/// </summary>
SqlOlapConnectionInfoBase Connection
{
get;
}
/// <summary>
/// Free any resources for this connection
/// </summary>
void Close();
}
/// <summary>
/// interface used by the objectexplorer. Allows us to "pool" the main connection
/// </summary>
internal interface IManagedConnection2 : IManagedConnection
{
}
/// <summary>
/// Implementation of IManagedConnection. Allows the use of a direct or indirect connection
/// in the object explorer that takes care of the connection.
/// </summary>
internal class ManagedConnection : IManagedConnection2
{
#region private members
private bool connectionAddedToActiveConnections = false;
private bool closeOnDispose = false;
private SqlOlapConnectionInfoBase connection;
private bool closed = false;
#endregion
#region Construction
/// <summary>
/// Create a new managed connection
/// </summary>
/// <param name="connection">connection wish to manage</param>
public ManagedConnection(SqlOlapConnectionInfoBase connection)
: this(connection, false)
{
}
/// <summary>
/// create a new managed connection.
/// </summary>
/// <param name="connection">connection</param>
/// <param name="attemptToPool">true if we are going to try and reuse the
/// connection if possible</param>
public ManagedConnection(SqlOlapConnectionInfoBase sourceConnection, bool attemptToPool)
{
// parameter check
if (sourceConnection == null)
{
throw new ArgumentNullException("sourceConnection");
}
// see if the connection can restrict access (single user mode)
IRestrictedAccess access = sourceConnection as IRestrictedAccess;
// see if it is cloneable
ICloneable cloneable = sourceConnection as ICloneable;
lock (ActiveConnections)
{
// if it's not single user mode then we can see if the object can be cloned
if (access == null || access.SingleConnection == false)
{
// if we are going to attempt to pool, see if the connection is in use
if (attemptToPool && !ActiveConnections.Contains(SharedConnectionUtil.GetConnectionKeyName(sourceConnection)))
{
// add it to the hashtable to indicate use.
ActiveConnections.Add(SharedConnectionUtil.GetConnectionKeyName(sourceConnection), sourceConnection);
this.connection = sourceConnection;
this.closeOnDispose = false;
this.connectionAddedToActiveConnections = true;
}
else if (cloneable != null)
{
this.connection = (SqlOlapConnectionInfoBase)cloneable.Clone();
this.closeOnDispose = true;
}
else if (sourceConnection is SqlConnectionInfoWithConnection)
{
this.connection = ((SqlConnectionInfoWithConnection)sourceConnection).Copy();
this.closeOnDispose = true;
}
}
}
// if everything else has failed just use to passed in connection.
if (this.connection == null)
{
this.connection = sourceConnection;
}
// always set the lock timeout to prevent the shell from not responding
if (this.connection is SqlConnectionInfoWithConnection)
{
// set lock_timeout to 10 seconds
((SqlConnectionInfoWithConnection)this.connection).ServerConnection.LockTimeout = 10;
}
}
#endregion
#region IDisposable implementation
public void Dispose()
{
Close();
}
#endregion
#region IManagedConnection implementation
/// <summary>
/// Connection
/// </summary>
public SqlOlapConnectionInfoBase Connection
{
get
{
return this.connection;
}
}
/// <summary>
/// Close the current connection if applicable.
/// </summary>
public void Close()
{
if (this.closed)
return;
if (this.closeOnDispose)
{
IDisposable disp = this.connection as IDisposable;
if (disp != null)
{
disp.Dispose();
}
}
else
{
// if we are not closing the connection and it is a sql connection then ensure it
// is left in the master database.
SqlConnectionInfoWithConnection sqlConnection = this.connection as SqlConnectionInfoWithConnection;
if (sqlConnection != null && sqlConnection.ServerConnection.DatabaseEngineType == DatabaseEngineType.Standalone)
{
try
{
sqlConnection.ServerConnection.ExecuteNonQuery("use [master]");
}
// don't error if this fails
catch
{ }
}
}
if (this.connectionAddedToActiveConnections)
{
lock (ActiveConnections)
{
ActiveConnections.Remove(SharedConnectionUtil.GetConnectionKeyName(connection));
}
}
this.connection = null;
this.closed = true;
}
#endregion
#region static helpers
/// <summary>
/// hashtable we use to keep track of actively used main connections
/// </summary>
private static Hashtable activeConnections = null;
private Hashtable ActiveConnections
{
get
{
if (activeConnections == null)
{
activeConnections = new Hashtable();
}
return activeConnections;
}
}
#endregion
}
}

View File

@@ -1,488 +0,0 @@
//
// 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.Xml;
using System.Collections;
using System.Diagnostics;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// SqlTools Parameters, used to define what goes into starting up a Workbench Form
/// AKA a dbCommander, AKA a "dialog"
/// These parameters are xml snippets
/// </summary>
public class STParameters
{
public XmlDocument m_doc;
/// <summary>
/// The data type we are interested in
/// </summary>
public enum STType { eNULL, eInt, eLong, eString };
/// <summary>
/// default constructor
/// </summary>
public STParameters()
{
//
// TODO: Add constructor logic here
//
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="xmlDoc">The xml snippet used to control the dbCommander</param>
public STParameters(XmlDocument xmlDoc)
{
m_doc = xmlDoc;
}
/// <summary>
/// Changing the xml snippet we are using
/// </summary>
/// <param name="xmlDoc">the new xml snippet</param>
public void SetDocument(XmlDocument xmlDoc)
{
m_doc = xmlDoc;
}
/// <summary>
/// Access to the xml we are using for dbCommander parameters
/// </summary>
/// <returns>our current parameters</returns>
public XmlDocument GetDocument()
{
return m_doc;
}
/// <summary>
/// Search for an xml tag, and return its value
/// </summary>
/// <param name="parameterName">the xml tag name</param>
/// <param name="value">the value of that tag</param>
/// <returns>flag that is true if the data was found, false if not</returns>
public bool GetBaseParam(string parameterName, ref object value)
{
XmlNodeList nodeList = null;
bool parameterExists;
if (m_doc == null)
return false;
parameterExists = false;
nodeList = m_doc.GetElementsByTagName(parameterName);
if (nodeList.Count > 1)
{
value = null;
}
else if (nodeList.Count != 0) // anything there?
{
try
{
XmlNode node = nodeList.Item(0);
if (null != node)
{
value = node.InnerText as object;
parameterExists = true;
}
}
catch (Exception /*e*/)
{
}
}
return parameterExists;
}
/// <summary>
/// Finds an existing xml tag, and sets it to a new value, or if the tag is not found
/// create it and set it's value
/// </summary>
/// <param name="parameterName">tag name</param>
/// <param name="value">new value</param>
/// <returns>flag that is true if the tag was set, false if not</returns>
public bool SetBaseParam(string parameterName, object value)
{
XmlNodeList nodeList;
bool success = false;
nodeList = m_doc.GetElementsByTagName(parameterName);
if (nodeList.Count == 1)
{
try
{
nodeList.Item(0).InnerText = (string)value;
success = true;
}
catch (InvalidCastException /*e*/)
{
success = false;
}
}
if (nodeList.Count == 0)
{
try
{
XmlElement xmlElement = m_doc.CreateElement(parameterName);
XmlNode root = m_doc.DocumentElement;
nodeList = m_doc.GetElementsByTagName("params");
if (nodeList.Count == 1 && value is string)
{
xmlElement.InnerText = (string)value;
nodeList.Item(0).InsertAfter(xmlElement, nodeList.Item(0).LastChild);
success = true;
}
}
catch (Exception e)
{
string sz = e.ToString();
success = false;
}
}
return success;
}
/// <summary>
/// Get back an interger parameter.
/// NOTE: if the tag exists, but it contains non-numeric data, this will throw
/// An exception of type 'System.FormatException'
/// with Additional information: Could not find any parsible digits.
/// </summary>
/// <param name="parameterName">xml tag name for the parameter of interest</param>
/// <param name="iValue">out value of parameter</param>
/// <returns>flag that is true if the data was found, false if not</returns>
public bool GetParam(string parameterName, out int value)
{
bool parameterExists = false;
value = 0;
try
{
object oAux = null;
if (parameterExists = GetBaseParam(parameterName, ref oAux))
{
try
{
value = Convert.ToInt32((string)oAux, 10); // data is always a string, it is the value of XmlNode.InnerText
}
catch (FormatException e)
{
Debug.WriteLine(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Non numeric data in tag: {0}", parameterName));
Debug.WriteLine(e.Message);
throw;
}
}
}
catch (InvalidCastException /*e*/)
{
}
return parameterExists;
}
/// <summary>
/// Accessor for a boolean parameter
/// NOTE: if the tag exists, but it contains non-numeric data, this will throw
/// An exception of type 'System.FormatException'
/// with Additional information: Could not find any parsible digits.
/// </summary>
/// <param name="parameterName">xml tag name for the parameter of interest</param>
/// <param name="value">out value of parameter</param>
/// <returns>flag that is true if the data was found, false if not</returns>
public bool GetParam(string parameterName, ref bool value)
{
bool parameterExists = false;
value = false;
try
{
object oAux = null;
if (parameterExists = GetBaseParam(parameterName, ref oAux))
{
try
{
value = Convert.ToBoolean((string)oAux, System.Globalization.CultureInfo.InvariantCulture); // data is always a string, it is the value of XmlNode.InnerText
}
catch (FormatException e)
{
Debug.WriteLine(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Non boolean data in tag: {0}", parameterName));
Debug.WriteLine(e.Message);
throw;
}
}
}
catch (InvalidCastException /*e*/)
{
}
return parameterExists;
}
/// <summary>
/// Accessor to a string parameter
/// </summary>
/// <param name="parameterName">xml tag name for the parameter of interest</param>
/// <param name="value">out value of parameter</param>
/// <returns>flag that is true if the data was found, false if not</returns>
public bool GetParam(string parameterName, ref string value)
{
bool parameterExists;
value = "";
parameterExists = false;
try
{
object oAux = null;
if (parameterExists = GetBaseParam(parameterName, ref oAux))
{
value = (string)oAux;
}
}
catch (InvalidCastException /*e*/)
{
}
return parameterExists;
}
/// <summary>
/// Accessor to long parameter (Int64)
/// NOTE: if the tag exists, but it contains non-numeric data, this will throw
/// An exception of type 'System.FormatException'
/// with Additional information: Could not find any parsible digits.
/// </summary>
/// <param name="parameterName">xml tag name for the parameter of interest</param>
/// <param name="value">out value of parameter</param>
/// <returns>flag that is true if the data was found, false if not</returns>
public bool GetParam(string parameterName, out long value)
{
bool parameterExists = false;
value = 0;
try
{
object oAux = null;
if (parameterExists = GetBaseParam(parameterName, ref oAux))
{
try
{
value = Convert.ToInt64((string)oAux, 10); // data is always a string, it is the value of XmlNode.InnerText
}
catch (FormatException e)
{
Debug.WriteLine(String.Format(System.Globalization.CultureInfo.CurrentCulture, "Non numeric data in tag: {0}", parameterName));
Debug.WriteLine(e.Message);
throw;
}
}
}
catch (InvalidCastException /*e*/)
{
}
return parameterExists;
}
/// <summary>
/// Set an int (Int32) parameter
/// </summary>
/// <param name="parameterName">tag name for parameter</param>
/// <param name="value">integer value</param>
/// <returns>true if set was successful, false if not</returns>
public bool SetParam(string parameterName, int value)
{
bool success;
success = SetBaseParam(parameterName, (object)value);
return success;
}
/// <summary>
/// Set a string parameter
/// </summary>
/// <param name="parameterName">tag name for parameter</param>
/// <param name="value">string value</param>
/// <returns>true if set was successful, false if not</returns>
public bool SetParam(string parameterName, string value)
{
bool success;
success = SetBaseParam(parameterName, (object)value);
return success;
}
/// <summary>
/// Set a long (Int64) parameter
/// </summary>
/// <param name="parameterName">tag name for parameter</param>
/// <param name="value">long value</param>
/// <returns>true if set was successful, false if not</returns>
public bool SetParam(string parameterName, long value)
{
bool success;
success = SetBaseParam(parameterName, (object)value);
return success;
}
/// <summary>
/// Get a string collection parameter
/// </summary>
/// <param name="parameterName">name of collection</param>
/// <param name="list">collection that gets filled up with parameters</param>
/// <param name="getInnerXml">true if we want to get at inner nodes, false if not</param>
/// <returns>true if parameter(s) exist</returns>
public bool GetParam(string parameterName, System.Collections.Specialized.StringCollection list, bool getInnerXml)
{
/// necessary for OALP objects path that is in an XML form
if (true == getInnerXml)
{
XmlNodeList nodeList;
bool parameterExists;
long lCount;
parameterExists = false;
nodeList = m_doc.GetElementsByTagName(parameterName);
list.Clear();
lCount = nodeList.Count;
if (lCount > 0)
{
parameterExists = true;
for (long i = 0; i < lCount; i++)
{
list.Add(nodeList.Item((int)i).InnerXml);
}
}
else
{
parameterExists = false;
}
return parameterExists;
}
else
{
return GetParam(parameterName, list);
}
}
/// <summary>
/// Access to a collection of parameters
/// </summary>
/// <param name="parameterName">name of collection</param>
/// <param name="list">list to fill with parameters</param>
/// <returns>parameter(s) exist</returns>
public bool GetParam(string parameterName, System.Collections.Specialized.StringCollection list)
{
XmlNodeList nodeList;
bool parameterExists;
long lCount;
parameterExists = false;
nodeList = m_doc.GetElementsByTagName(parameterName);
list.Clear();
lCount = nodeList.Count;
if (lCount > 0)
{
parameterExists = true;
for (long i = 0; i < lCount; i++)
{
list.Add(nodeList.Item((int)i).InnerText);
}
}
else
{
parameterExists = false;
}
return parameterExists;
}
public bool GetParam(string parameterName, ref ArrayList list)
{
System.Collections.Specialized.StringCollection stringList = new System.Collections.Specialized.StringCollection();
bool parameterExists = GetParam(parameterName, stringList);
list.Clear();
if (!parameterExists)
{
return false;
}
else
{
for (int i = 0; i < stringList.Count; i++)
{
list.Add(stringList[i]);
}
return true;
}
}
/// <summary>
/// This function does nothing but return false
/// </summary>
/// <param name="parameterName">ignored</param>
/// <param name="type">ignored</param>
/// <returns>always false</returns>
public bool GetParamType(string parameterName, STType type)
{
bool whatever = false;
return whatever;
}
/// <summary>
/// This function does nothing but return false
/// </summary>
/// <param name="parameterName">ignored</param>
/// <param name="type">ignored</param>
/// <returns>always false</returns>
public bool SetParamType(string parameterName, STType type)
{
bool whatever = false;
return whatever;
}
}
}

View File

@@ -1,108 +0,0 @@
//
// 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 Microsoft.SqlServer.Management.AzureCredential;
using Microsoft.SqlServer.Management.Common;
//using Microsoft.SqlServer.Management.Smo.RegSvrEnum;
using SFC = Microsoft.SqlServer.Management.Sdk.Sfc;
//using Microsoft.SqlServer.StorageClient;
//using Microsoft.SqlServer.Management.SqlMgmt;
/// <summary>
/// Summary description for SharedConectionUtil
/// Moved GetConnectionName static call in a public class acessible for both
/// OEXM and OE
/// </summary>
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
internal class SharedConnectionUtil
{
public SharedConnectionUtil()
{
}
/// <summary>
///
/// </summary>
/// <param name="ci"></param>
/// <returns></returns>
public static string GetConnectionKeyName(SqlOlapConnectionInfoBase ci)
{
//// Note that these strings are not localized. The returned string is used by OE in a
//// hash of connections so it can tell if it already has such a connection open. This
//// string is never seen by the user. For the string seen by the user, see
//// ServerNameHandler.cs.
string displayName = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0} (", ci.ServerName);
if (!string.IsNullOrEmpty(ci.DatabaseName))
{
displayName += ", " + ci.DatabaseName;
}
return displayName;
//switch (ci.ServerType)
//{
// case ConnectionType.AzureStorage:
// AzureStorageConnectionInfo azureCI = ci as AzureStorageConnectionInfo;
// displayName = "AzureStorage," + azureCI.BlobClient.BaseUri;
// break;
// case ConnectionType.AzureAccount:
// if (ci is CertificateBasedAuthenticationInfo)
// {
// displayName = "AzureSubscription," + (ci as CertificateBasedAuthenticationInfo).SubscriptionId;
// }
// else
// {
// displayName = "AzureSubscription";
// }
// break;
// case ConnectionType.Sql:
// displayName += "SQLServer";
// SqlConnectionInfo sqlCi = ci as SqlConnectionInfo;
// if (sqlCi.UseIntegratedSecurity == true)
// {
// displayName += ", trusted";
// }
// else
// {
// displayName += String.Format(System.Globalization.CultureInfo.InvariantCulture, ", user = {0}", sqlCi.UserName);
// //In Cloud a user can have access to only a few UDBs without access to master DB
// // and hence need to show different OE hierarchy trees for each DB
// //Same is the case with a contained user.
// if (ServerInfoCache.GetDatabaseEngineType(ci.ServerName) == DatabaseEngineType.SqlAzureDatabase
// || SFC.ExecuteSql.GetDatabaseEngineType(ci) == DatabaseEngineType.SqlAzureDatabase
// || SFC.ExecuteSql.IsContainedAuthentication(ci))
// {
// if (!string.IsNullOrEmpty(ci.DatabaseName))
// {
// displayName += ", " + ci.DatabaseName;
// }
// }
// }
// break;
// case ConnectionType.Olap:
// displayName += "OLAP";
// break;
// case ConnectionType.SqlCE:
// displayName += "SqlCE";
// break;
// case ConnectionType.ReportServer:
// displayName += "Rs";
// displayName += String.Format(System.Globalization.CultureInfo.InvariantCulture, ", connection = {0}", ci.ConnectionString);
// break;
// case ConnectionType.IntegrationServer:
// displayName += "SSIS";
// break;
//}
//displayName += ")";
//return displayName;
}
}
}

View File

@@ -1,657 +0,0 @@
//
// 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.Text;
using System.Xml;
using System.Threading;
using System.IO;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Diagnostics;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using System.Data.SqlClient;
using System.Collections;
using System.Reflection;
using System.Globalization;
using SMO = Microsoft.SqlServer.Management.Smo;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Internal reusable helpers
/// </summary>
internal class Utils
{
/// <summary>
/// only static methods
/// </summary>
private Utils() { }
/// <summary>
/// returns all instances of the given custom attribute on a given object
/// </summary>
/// <param name="objectToGetAttributeFrom"></param>
/// <param name="customAttribute"></param>
/// <returns></returns>
public static Attribute GetCustomAttribute(object objectToGetAttributeFrom, Type customAttribute)
{
//first, see if the object implemented this interface to override standard behavior
System.Reflection.ICustomAttributeProvider attribProvider = objectToGetAttributeFrom as System.Reflection.ICustomAttributeProvider;
if (attribProvider == null)
{
//if not, get it from its type
attribProvider = (System.Reflection.ICustomAttributeProvider)objectToGetAttributeFrom.GetType();
}
object[] attribs = attribProvider.GetCustomAttributes(customAttribute, true);
if (attribs != null && attribs.Length > 0)
{
//NOTE: important that we'll always use the first one in collection.
//Our implementation of ICustomAttributeProvider knows about that and
//relies on this behavior
return attribs[0] as Attribute;
}
return null;
}
/// <summary>
/// called to create SqlConnectionInfo out of the given CDataContainer object
/// </summary>
/// <param name="dc"></param>
/// <returns></returns>
public static SqlConnectionInfo GetSqlConnectionInfoFromDataContainer(CDataContainer dc)
{
if (dc != null)
{
// we may have been given conneciton information by the object explorer. in which case there is no need
// to build it ourselves.
SqlConnectionInfo result = dc.ConnectionInfo as SqlConnectionInfo;
if (result == null)
{
throw new InvalidOperationException();
}
return result;
}
else
{
return null;
}
}
public static int InitialTreeViewWidth
{
get
{
return 175;
}
}
/// <summary>
/// Try to set the CLR thread name.
/// Will not throw if the name is already set.
/// </summary>
/// <param name="name"></param>
public static void TrySetThreadName(String name)
{
try
{
System.Threading.Thread.CurrentThread.Name = name;
}
catch (InvalidOperationException)
{ }
}
public static bool IsKatmaiOrLater(int version)
{
return (10 <= version);
}
public static bool IsKjOrLater(ServerVersion version)
{
return (version.Major > 10
|| (version.Major == 10 && version.Minor >= 50));
}
public static bool IsSql11OrLater(ServerVersion version)
{
return IsSql11OrLater(version.Major);
}
public static bool IsSql11OrLater(int versionMajor)
{
return (versionMajor >= 11);
}
public static bool IsSql12OrLater(ServerVersion version)
{
return IsSql12OrLater(version.Major);
}
public static bool IsSql12OrLater(int versionMajor)
{
return (versionMajor >= 12);
}
public static bool IsSql13OrLater(ServerVersion version)
{
return IsSql13OrLater(version.Major);
}
public static bool IsSql13OrLater(int versionMajor)
{
return (versionMajor >= 13);
}
public static bool IsSql14OrLater(ServerVersion version)
{
return IsSql14OrLater(version.Major);
}
public static bool IsSql14OrLater(int versionMajor)
{
return (versionMajor >= 14);
}
/// <summary>
/// Check if the version is SQL 2016 SP1 or later.
/// </summary>
/// <param name="version"></param>
/// <returns>true if the version is SQL 2016 SP1 or later, false otherwise</returns>
public static bool IsSql13SP1OrLater(Version version)
{
return (version >= new Version(13, 0, 3510));
}
public static bool IsXTPSupportedOnServer(SMO.Server server)
{
bool isXTPSupported = false;
if (server.ConnectionContext.ExecuteScalar("SELECT SERVERPROPERTY('IsXTPSupported')") != DBNull.Value)
{
isXTPSupported = server.IsXTPSupported;
}
return isXTPSupported;
}
/// <summary>
/// Returns true if given database has memory optimized filegroup on given server.
/// </summary>
/// <param name="server"></param>
/// <param name="dbName"></param>
/// <returns></returns>
public static bool HasMemoryOptimizedFileGroup(SMO.Server server, string dbName)
{
bool hasMemoryOptimizedFileGroup = false;
if (server.ServerType != DatabaseEngineType.SqlAzureDatabase)
{
string query = string.Format(CultureInfo.InvariantCulture,
"select top 1 1 from [{0}].sys.filegroups where type = 'FX'",
CUtils.EscapeString(dbName, ']'));
if (server.ConnectionContext.ExecuteScalar(query) != null)
{
hasMemoryOptimizedFileGroup = true;
}
}
return hasMemoryOptimizedFileGroup;
}
public static bool IsPolybasedInstalledOnServer(SMO.Server server)
{
bool isPolybaseInstalled = false;
if (server.IsSupportedProperty("IsPolyBaseInstalled"))
{
isPolybaseInstalled = server.IsPolyBaseInstalled;
}
return isPolybaseInstalled;
}
/// <summary>
/// Returns true if current user has given permission on given server.
/// </summary>
/// <param name="server"></param>
/// <param name="permissionName"></param>
/// <returns></returns>
public static bool HasPermissionOnServer(SMO.Server server, string permissionName)
{
return Convert.ToBoolean(server.ConnectionContext.ExecuteScalar(
string.Format(CultureInfo.InvariantCulture,
"SELECT HAS_PERMS_BY_NAME(null, null, '{0}');",
permissionName)));
}
public static bool FilestreamEnabled(SMO.Server svr)
{
bool result = false;
if (svr != null)
{
if (IsKatmaiOrLater(svr.Information.Version.Major)
&& svr.ServerType != DatabaseEngineType.SqlAzureDatabase) //Azure doesn't support filestream
{
if (svr.Configuration.FilestreamAccessLevel.RunValue != 0)
{
result = true;
}
}
}
return result;
}
public static bool IsYukonOrAbove(SMO.Server server)
{
return server.Version.Major >= 9;
}
public static bool IsBelowYukon(SMO.Server server)
{
return server.Version.Major < 9;
}
public static string MakeSqlBracket(string s)
{
return "[" + s.Replace("]", "]]") + "]";
}
}
/// <summary>
/// Public reusable helpers
/// </summary>
public class SqlMgmtUtils
{
/// <summary>
/// only static methods
/// </summary>
private SqlMgmtUtils() { }
/// <summary>
/// Returns whether the server is in AS Azure
/// </summary>
/// <param name="serverName"></param>
/// <returns></returns>
public static bool IsASAzure(string serverName)
{
return !string.IsNullOrEmpty(serverName) && serverName.StartsWith("asazure://", StringComparison.OrdinalIgnoreCase);
}
}
/// <summary>
/// Summary description for CUtils.
/// </summary>
internal class CUtils
{
private const int ObjectPermissionsDeniedErrorNumber = 229;
private const int ColumnPermissionsDeniedErrorNumber = 230;
public CUtils()
{
//
// TODO: Add constructor logic here
//
}
public static void UseMaster(SMO.Server server)
{
server.ConnectionContext.ExecuteNonQuery("use master");
}
/// <summary>
/// Get a SMO Server object that is connected to the connection
/// </summary>
/// <param name="ci">Conenction info</param>
/// <returns>Smo Server object for the connection</returns>
public static Microsoft.SqlServer.Management.Smo.Server GetSmoServer(IManagedConnection mc)
{
SqlOlapConnectionInfoBase ci = mc.Connection;
if (ci == null)
{
throw new ArgumentNullException("ci");
}
SMO.Server server = null;
// see what type of connection we have been passed
SqlConnectionInfoWithConnection ciWithCon = ci as SqlConnectionInfoWithConnection;
if (ciWithCon != null)
{
server = new SMO.Server(ciWithCon.ServerConnection);
}
else
{
SqlConnectionInfo sqlCi = ci as SqlConnectionInfo;
if (sqlCi != null)
{
server = new SMO.Server(new ServerConnection(sqlCi));
}
}
if (server == null)
{
throw new InvalidOperationException();
}
return server;
}
public static int GetServerVersion(SMO.Server server)
{
return server.Information.Version.Major;
}
/// <summary>
/// Determines the oldest date based on the type of time units and the number of time units
/// </summary>
/// <param name="numUnits"></param>
/// <param name="typeUnits"></param>
/// <returns></returns>
public static DateTime GetOldestDate(int numUnits, TimeUnitType typeUnits)
{
DateTime result = DateTime.Now;
switch (typeUnits)
{
case TimeUnitType.Week:
{
result = (DateTime.Now).AddDays(-1 * 7 * numUnits);
break;
}
case TimeUnitType.Month:
{
result = (DateTime.Now).AddMonths(-1 * numUnits);
break;
}
case TimeUnitType.Year:
{
result = (DateTime.Now).AddYears(-1 * numUnits);
break;
}
default:
{
result = (DateTime.Now).AddDays(-1 * numUnits);
break;
}
}
return result;
}
public static string TokenizeXml(string s)
{
if (null == s) return String.Empty;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (char c in s)
{
switch (c)
{
case '<':
sb.Append("&lt;");
break;
case '>':
sb.Append("&gt;");
break;
case '&':
sb.Append("&amp;");
break;
default:
sb.Append(c);
break;
}
}
return sb.ToString();
}
/// <summary>
/// Tries to get the SqlException out of an Enumerator exception
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public static SqlException GetSqlException(Exception e)
{
SqlException sqlEx = null;
Exception exception = e;
while (exception != null)
{
sqlEx = exception as SqlException;
if (null != sqlEx)
{
break;
}
exception = exception.InnerException;
}
return sqlEx;
}
/// <summary>
/// computes the name of the machine based on server's name (as returned by smoServer.Name)
/// </summary>
/// <param name="sqlServerName">name of server ("",".","Server","Server\Instance",etc)</param>
/// <returns>name of the machine hosting sql server instance</returns>
public static string GetMachineName(string sqlServerName)
{
System.Diagnostics.Debug.Assert(sqlServerName != null);
string machineName = sqlServerName;
if (sqlServerName.Trim().Length != 0)
{
// [0] = machine, [1] = instance (if any)
return sqlServerName.Split('\\')[0];
}
else
{
// we have default instance of default machine
return machineName;
}
}
/// <summary>
/// Determines if a SqlException is Permission denied exception
/// </summary>
/// <param name="sqlException"></param>
/// <returns></returns>
public static bool IsPermissionDeniedException(SqlException sqlException)
{
bool isPermDenied = false;
if (null != sqlException.Errors)
{
foreach (SqlError sqlError in sqlException.Errors)
{
int errorNumber = GetSqlErrorNumber(sqlError);
if ((ObjectPermissionsDeniedErrorNumber == errorNumber) ||
(ColumnPermissionsDeniedErrorNumber == errorNumber))
{
isPermDenied = true;
break;
}
}
}
return isPermDenied;
}
/// <summary>
/// Returns the error number of a sql exeception
/// </summary>
/// <param name="sqlerror"></param>
/// <returns></returns>
public static int GetSqlErrorNumber(SqlError sqlerror)
{
return sqlerror.Number;
}
/// <summary>
/// Function doubles up specified character in a string
/// </summary>
/// <param name="s"></param>
/// <param name="cEsc"></param>
/// <returns></returns>
public static String EscapeString(string s, char cEsc)
{
StringBuilder sb = new StringBuilder(s.Length * 2);
foreach (char c in s)
{
sb.Append(c);
if (cEsc == c)
sb.Append(c);
}
return sb.ToString();
}
/// <summary>
/// Function doubles up ']' character in a string
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static String EscapeStringCBracket(string s)
{
return CUtils.EscapeString(s, ']');
}
/// <summary>
/// Function doubles up '\'' character in a string
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static String EscapeStringSQuote(string s)
{
return CUtils.EscapeString(s, '\'');
}
/// <summary>
/// Function removes doubled up specified character from a string
/// </summary>
/// <param name="s"></param>
/// <param name="cEsc"></param>
/// <returns></returns>
public static String UnEscapeString(string s, char cEsc)
{
StringBuilder sb = new StringBuilder(s.Length);
bool foundBefore = false;
foreach (char c in s)
{
if (cEsc == c) // character to unescape
{
if (foundBefore) // skip second occurrence
{
foundBefore = false;
}
else // set the flag to skip next time around
{
sb.Append(c);
foundBefore = true;
}
}
else
{
sb.Append(c);
foundBefore = false;
}
}
return sb.ToString();
}
/// <summary>
/// Function removes doubled up ']' character from a string
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static String UnEscapeStringCBracket(string s)
{
return CUtils.UnEscapeString(s, ']');
}
/// <summary>
/// Function removes doubled up '\'' character from a string
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static String UnEscapeStringSQuote(string s)
{
return CUtils.UnEscapeString(s, '\'');
}
/// <summary>
/// Get the windows login name with the domain portion in all-caps
/// </summary>
/// <param name="windowsLoginName">The windows login name</param>
/// <returns>The windows login name with the domain portion in all-caps</returns>
public static string CanonicalizeWindowsLoginName(string windowsLoginName)
{
string result;
int lastBackslashIndex = windowsLoginName.LastIndexOf("\\", StringComparison.Ordinal);
if (-1 != lastBackslashIndex)
{
string domainName = windowsLoginName.Substring(0, lastBackslashIndex).ToUpperInvariant();
string afterDomain = windowsLoginName.Substring(lastBackslashIndex);
result = String.Concat(domainName, afterDomain);
}
else
{
result = windowsLoginName;
}
return result;
}
}
/// <summary>
/// Enum of time units types ( used in cleaning up history based on age )
/// </summary>
internal enum TimeUnitType
{
Day,
Week,
Month,
Year
}
/// <summary>
/// Object used to populate default language in
/// database and user dialogs.
/// </summary>
internal class LanguageDisplay
{
private SMO.Language language;
public string LanguageAlias
{
get
{
return language.Alias;
}
}
public SMO.Language Language
{
get
{
return language;
}
}
public LanguageDisplay(SMO.Language language)
{
this.language = language;
}
public override string ToString()
{
return language.Alias;
}
}
}

View File

@@ -9,8 +9,9 @@ using System.Collections.Generic;
using System.Globalization;
using Microsoft.SqlServer.Diagnostics.STrace;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.Win32;
using SizeUnits = Microsoft.SqlTools.ServiceLayer.Admin.DbSize.SizeUnits;
using SizeUnits = Microsoft.SqlTools.ServiceLayer.Management.DbSize.SizeUnits;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -20,6 +20,7 @@ using System.Globalization;
using System.Data.SqlClient;
using System.Collections.Generic;
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -17,6 +17,7 @@ using System.Data.SqlClient;
using System.Collections.Generic;
using System.Diagnostics;
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
@@ -117,8 +118,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// </remarks>
public DatabaseData(CDataContainer context)
{
this.name = String.Empty;
this.owner = String.Empty;
this.name = string.Empty;
this.owner = string.Empty;
this.restrictAccess = DatabaseUserAccess.Multiple;
this.isReadOnly = false;
this.databaseState = DatabaseStatus.Normal;
@@ -176,7 +177,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
this.targetRecoveryTime = 0;
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
//in katmai var decimal going to be true by default

View File

@@ -10,6 +10,7 @@ using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -7,6 +7,7 @@ using System.ComponentModel;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -10,6 +10,7 @@ using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
using System.Collections.Generic;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -5,6 +5,7 @@
using System.ComponentModel;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -10,6 +10,7 @@ using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
using System.Collections.Generic;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -6,6 +6,7 @@
using System.ComponentModel;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlTools.ServiceLayer.Management;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{

View File

@@ -11,6 +11,7 @@ using System.Linq;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Management;
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
namespace Microsoft.SqlTools.ServiceLayer.Admin

View File

@@ -6,6 +6,7 @@
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlTools.Utility;
using System;
using System.Collections;