// // 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.Data.SqlClient; using System.Globalization; using System.IO; using System.Reflection; using System.Text; using System.Threading; using System.Xml; using Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Diagnostics; using Microsoft.SqlServer.Management.Sdk.Sfc; using SMO = Microsoft.SqlServer.Management.Smo; namespace Microsoft.SqlTools.ServiceLayer.Management { /// /// Internal reusable helpers /// internal class Utils { /// /// only static methods /// private Utils() { } /// /// returns all instances of the given custom attribute on a given object /// /// /// /// 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; } /// /// called to create SqlConnectionInfo out of the given CDataContainer object /// /// /// 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; } } /// /// Try to set the CLR thread name. /// Will not throw if the name is already set. /// /// 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); } /// /// Check if the version is SQL 2016 SP1 or later. /// /// /// true if the version is SQL 2016 SP1 or later, false otherwise 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; } /// /// Returns true if given database has memory optimized filegroup on given server. /// /// /// /// 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; } /// /// Returns true if current user has given permission on given server. /// /// /// /// 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("]", "]]") + "]"; } /// /// Some calendars, such as the UmAlQuraCalendar, support an upper date range that is earlier than MaxValue. /// In these cases, trying to access MaxValue in variable assignments or formatting and parsing operations can throw /// an ArgumentOutOfRangeException. Rather than retrieving the value of DateTime.MaxValue, you can retrieve the value /// of the specified culture's latest valid date value from the /// System.Globalization.CultureInfo.DateTimeFormat.Calendar.MaxSupportedDateTime property. /// http://msdn.microsoft.com/en-us/library/system.datetime.maxvalue(v=VS.90).aspx /// /// public static DateTime GetMaxCultureDateTime() { CultureInfo currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; return currentCulture.DateTimeFormat.Calendar.MaxSupportedDateTime; } } /// /// Public reusable helpers /// public class SqlMgmtUtils { /// /// only static methods /// private SqlMgmtUtils() { } /// /// Returns whether the server is in AS Azure /// /// /// public static bool IsASAzure(string serverName) { return !string.IsNullOrEmpty(serverName) && serverName.StartsWith("asazure://", StringComparison.OrdinalIgnoreCase); } } /// /// Summary description for CUtils. /// 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"); } /// /// Get a SMO Server object that is connected to the connection /// /// Conenction info /// Smo Server object for the connection 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; } /// /// Determines the oldest date based on the type of time units and the number of time units /// /// /// /// 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("<"); break; case '>': sb.Append(">"); break; case '&': sb.Append("&"); break; default: sb.Append(c); break; } } return sb.ToString(); } /// /// Tries to get the SqlException out of an Enumerator exception /// /// /// 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; } /// /// computes the name of the machine based on server's name (as returned by smoServer.Name) /// /// name of server ("",".","Server","Server\Instance",etc) /// name of the machine hosting sql server instance 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; } } /// /// Determines if a SqlException is Permission denied exception /// /// /// 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; } /// /// Returns the error number of a sql exeception /// /// /// public static int GetSqlErrorNumber(SqlError sqlerror) { return sqlerror.Number; } /// /// Function doubles up specified character in a string /// /// /// /// public static String EscapeString(string s, char cEsc) { if (string.IsNullOrWhiteSpace(s)) { return s; } StringBuilder sb = new StringBuilder(s.Length * 2); foreach (char c in s) { sb.Append(c); if (cEsc == c) sb.Append(c); } return sb.ToString(); } /// /// Function doubles up ']' character in a string /// /// /// public static String EscapeStringCBracket(string s) { return CUtils.EscapeString(s, ']'); } /// /// Function doubles up '\'' character in a string /// /// /// public static String EscapeStringSQuote(string s) { return CUtils.EscapeString(s, '\''); } /// /// Function removes doubled up specified character from a string /// /// /// /// 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(); } /// /// Function removes doubled up ']' character from a string /// /// /// public static String UnEscapeStringCBracket(string s) { return CUtils.UnEscapeString(s, ']'); } /// /// Function removes doubled up '\'' character from a string /// /// /// public static String UnEscapeStringSQuote(string s) { return CUtils.UnEscapeString(s, '\''); } /// /// Get the windows login name with the domain portion in all-caps /// /// The windows login name /// The windows login name with the domain portion in all-caps 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; } } /// /// Enum of time units types ( used in cleaning up history based on age ) /// internal enum TimeUnitType { Day, Week, Month, Year } /// /// Object used to populate default language in /// database and user dialogs. /// 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; } } }