Enabling Files Tab to the database properties (#2169)

* sending dsc values to ADS

* modifying dsc method with unsupportable property IsValuedefault

* getting the options and added a bool flag to maintian checkbox for secondary to save

* sending data to ads

* Ready for PR with minimal changes of loading UI as expected, TODO:saving logic

* Excluding maxdop and resumable options from primary value conversion for 1/0's

* Adding Id to the info, as we cannot depend on names, as names can be altered in future

* saving successfully, todo-diff servers, script (secondary - primary compare and dont update),test, send null for unsupported

* adding nullable dsc for unsupported servers

* fixing script generation for some properties that are not touched. the generated script is unharmed but unnecessary here

* adding test conditions for database scoped configurations

* adding switch case method to get the values

* Removing Loc string for the TSQL options

* removing unnecessary using statement

* sending required data, verify autogrowth...

* using fullTextIndexing to open the files tab for sql server and not to other servers

* Adding test case and fixing createDatabase issue

* sending files as objecinfo

* Update src/Microsoft.SqlTools.ServiceLayer/Admin/Database/DatabasePrototype130.cs

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* comment update

* preparing filegroup and filetype options

* sending required all fields

* saving file code changes, need more to work

* Saving file is completed, todo:edit  & remove

* Logic to remove the file

* add,edit,save working

* cleaning merge conflicts accidentally added code

* Adding tests to validates Files by adding, removing, updating files

* adding comments

* all working including tests, except fileStream size question

* code review comments updates

* memoryoptimized filegroups should be part of filestream group

* failing tests fix

* Modify tests by create database using SqlTestDb

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs

Co-authored-by: Cory Rivera <corivera@microsoft.com>

* fixing test

* commenting remove file testing as failing pipeline but passing locally

* using enum for type

* trying to fix the test in server, removed the complaining file from test

* removing fulltext param and test fix

* fixing the path..

* test fix

* missing conflict resolving

---------

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
Co-authored-by: Cory Rivera <corivera@microsoft.com>
This commit is contained in:
Sai Avishkar Sreerama
2023-08-29 11:24:31 -05:00
committed by GitHub
parent 41ae066b46
commit 07c8069cfa
7 changed files with 314 additions and 51 deletions

View File

@@ -843,6 +843,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
private class FileData
{
public int id;
public string name;
public string physicalName;
public string folder;
@@ -859,6 +860,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="type"></param>
public FileData(DatabasePrototype parent, FileType type)
{
this.id = 0;
this.name = String.Empty;
this.physicalName = String.Empty;
this.folder = String.Empty;
@@ -879,6 +881,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
this.autogrowth = new Autogrowth(parent, file);
this.name = file.Name;
this.id = file.ID;
if (file.FileName.EndsWith(":", StringComparison.Ordinal))
{
@@ -923,6 +926,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
this.autogrowth = new Autogrowth(parent, file);
this.name = file.Name;
this.id = file.ID;
try
{
@@ -960,6 +964,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="other"></param>
public FileData(FileData other)
{
this.id = other.id;
this.name = other.name;
this.physicalName = other.physicalName;
this.folder = other.folder;
@@ -1001,6 +1006,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
#region properties
/// <summary>
/// The ID of the file
/// </summary>
public int ID
{
get { return this.currentState.id; }
set
{
this.currentState.id = value;
this.database.NotifyObservers();
}
}
/// <summary>
/// The logical name of the file, without extension
/// </summary>

View File

@@ -22,6 +22,7 @@ using System.IO;
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
using System.Collections.Specialized;
using Microsoft.SqlTools.SqlCore.Utility;
using System.Collections.Concurrent;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
@@ -39,10 +40,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
private static readonly Dictionary<RecoveryModel, string> displayRecoveryModels = new Dictionary<RecoveryModel, string>();
private static readonly Dictionary<PageVerify, string> displayPageVerifyOptions = new Dictionary<PageVerify, string>();
private static readonly Dictionary<DatabaseUserAccess, string> displayRestrictAccessOptions = new Dictionary<DatabaseUserAccess, string>();
private static readonly ConcurrentDictionary<FileType, string> displayFileTypes = new ConcurrentDictionary<FileType, string>();
private static readonly Dictionary<string, CompatibilityLevel> compatLevelEnums = new Dictionary<string, CompatibilityLevel>();
private static readonly Dictionary<string, ContainmentType> containmentTypeEnums = new Dictionary<string, ContainmentType>();
private static readonly Dictionary<string, RecoveryModel> recoveryModelEnums = new Dictionary<string, RecoveryModel>();
private static readonly Dictionary<string, FileType> fileTypesEnums = new Dictionary<string, FileType>();
internal static readonly string[] AzureEditionNames;
internal static readonly string[] AzureBackupLevels;
@@ -81,6 +84,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
displayRestrictAccessOptions.Add(DatabaseUserAccess.Single, SR.prototype_db_prop_restrictAccess_value_single);
displayRestrictAccessOptions.Add(DatabaseUserAccess.Restricted, SR.prototype_db_prop_restrictAccess_value_restricted);
displayFileTypes.TryAdd(FileType.Data, SR.prototype_file_dataFile);
displayFileTypes.TryAdd(FileType.Log, SR.prototype_file_logFile);
displayFileTypes.TryAdd(FileType.FileStream, SR.prototype_file_filestreamFile);
DscOnOffOptions = new[]{
CommonConstants.DatabaseScopedConfigurations_Value_On,
CommonConstants.DatabaseScopedConfigurations_Value_Off
@@ -111,6 +118,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
recoveryModelEnums.Add(displayRecoveryModels[key], key);
}
foreach (FileType key in displayFileTypes.Keys)
{
fileTypesEnums.Add(displayFileTypes[key], key);
}
// Azure SLO info is invariant of server information, so set up static objects we can return later
var editions = AzureSqlDbHelper.GetValidAzureEditionOptions();
@@ -203,6 +214,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).PageVerify = displayPageVerifyOptions[smoDatabase.PageVerify];
((DatabaseInfo)databaseViewInfo.ObjectInfo).TargetRecoveryTimeInSec = smoDatabase.TargetRecoveryTime;
// Files tab is only supported in SQL Server, but files exists for all servers and used in detach database, cannot depend on files property to check the supportability
((DatabaseInfo)databaseViewInfo.ObjectInfo).IsFilesTabSupported = true;
}
if (prototype is DatabasePrototype160)
@@ -211,6 +224,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
databaseScopedConfigurationsCollection = smoDatabase.IsSupportedObject<DatabaseScopedConfiguration>() ? smoDatabase.DatabaseScopedConfigurations : null;
databaseViewInfo.FileTypesOptions = displayFileTypes.Values.ToArray();
// Get file groups names
GetFileGroupNames(smoDatabase, databaseViewInfo);
}
databaseViewInfo.DscOnOffOptions = DscOnOffOptions;
databaseViewInfo.DscElevateOptions = DscElevateOptions;
@@ -263,7 +280,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
var smoDatabase = dataContainer.SqlDialogSubject as Database;
if (smoDatabase != null)
{
databaseViewInfo.Files = GetDatabaseFiles(smoDatabase);
((DatabaseInfo)databaseViewInfo.ObjectInfo).Files = GetDatabaseFiles(smoDatabase);
}
}
}
@@ -605,7 +622,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
if (database.Owner != null && database.Owner != SR.general_default && viewParams.IsNewObject)
if (database.Owner != null && database.Owner != SR.general_default)
{
prototype.Owner = database.Owner;
}
@@ -681,6 +698,61 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
if (!viewParams.IsNewObject && database.Files != null)
{
HashSet<int> fileIdsToRemove = new HashSet<int>(prototype.Files.Select(file => file.ID));
foreach (var file in database.Files)
{
// Add a New file
if (file.Id == 0)
{
DatabaseFilePrototype newFile = new DatabaseFilePrototype(dataContainer, prototype, fileTypesEnums[file.Type]);
newFile.Name = file.Name;
newFile.InitialSize = (int)file.SizeInMb;
newFile.PhysicalName = file.FileNameWithExtension;
newFile.DatabaseFileType = fileTypesEnums[file.Type];
newFile.Exists = false;
newFile.Autogrowth = GetAutogrowth(prototype, file);
if (!string.IsNullOrEmpty(file.Path.Trim()))
{
newFile.Folder = Utility.DatabaseUtils.ConvertToLocalMachinePath(Path.GetFullPath(file.Path));
}
// Log file do not support file groups
if (fileTypesEnums[file.Type] != FileType.Log)
{
FilegroupPrototype fileGroup = new FilegroupPrototype(prototype);
fileGroup.Name = file.FileGroup;
newFile.FileGroup = fileGroup;
}
// Add newFile to the prototype files
prototype.Files.Add(newFile);
}
// Edit file properties: updating the existed files with modified data
else
{
var existedFile = prototype.Files.FirstOrDefault(x => x.ID == file.Id);
if (existedFile != null)
{
fileIdsToRemove.Remove(file.Id);
existedFile.Name = file.Name;
existedFile.InitialSize = (int)file.SizeInMb;
existedFile.Autogrowth = GetAutogrowth(prototype, file);
}
}
}
// Remove the file
foreach (var currentFile in prototype.Files)
{
if (fileIdsToRemove.Contains(currentFile.ID))
{
currentFile.Removed = true;
}
}
}
// AutoCreateStatisticsIncremental can only be set when AutoCreateStatistics is enabled
prototype.AutoCreateStatisticsIncremental = database.AutoCreateIncrementalStatistics;
prototype.AutoCreateStatistics = database.AutoCreateStatistics;
@@ -738,6 +810,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
private Autogrowth GetAutogrowth(DatabasePrototype prototype, DatabaseFile file)
{
Autogrowth fileAutogrowth = new Autogrowth(prototype);
fileAutogrowth.IsEnabled = file.IsAutoGrowthEnabled;
bool isGrowthInPercent = file.AutoFileGrowthType == FileGrowthType.Percent;
fileAutogrowth.IsGrowthInPercent = isGrowthInPercent;
fileAutogrowth.GrowthInPercent = isGrowthInPercent ? (int)file.AutoFileGrowth : fileAutogrowth.GrowthInPercent;
fileAutogrowth.GrowthInMegabytes = !isGrowthInPercent ? (int)file.AutoFileGrowth : fileAutogrowth.GrowthInMegabytes;
fileAutogrowth.MaximumFileSizeInMegabytes = (int)((0.0 <= file.MaxSizeLimitInMb) ? file.MaxSizeLimitInMb : 0.0);
fileAutogrowth.IsGrowthRestricted = file.MaxSizeLimitInMb > 0.0;
return fileAutogrowth;
}
/// <summary>
/// Get supported database collations for this server.
/// </summary>
@@ -898,10 +984,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
filesList.Add(new DatabaseFile()
{
Id = file.ID,
Name = file.Name,
Type = FileType.Data.ToString(),
Path = Path.GetDirectoryName(file.FileName),
FileGroup = fileGroup.Name
Type = file.Parent.FileGroupType == FileGroupType.RowsFileGroup ? displayFileTypes[FileType.Data] : displayFileTypes[FileType.FileStream],
Path = Utility.DatabaseUtils.ConvertToLocalMachinePath(Path.GetDirectoryName(file.FileName)),
FileGroup = fileGroup.Name,
FileNameWithExtension = Path.GetFileName(file.FileName),
SizeInMb = ByteConverter.ConvertKbtoMb(file.Size),
AutoFileGrowth = file.GrowthType == FileGrowthType.Percent ? file.Growth : ByteConverter.ConvertKbtoMb(file.Growth),
AutoFileGrowthType = file.GrowthType,
MaxSizeLimitInMb = file.MaxSize == -1 ? file.MaxSize : ByteConverter.ConvertKbtoMb(file.MaxSize),
IsAutoGrowthEnabled = file.GrowthType != FileGrowthType.None,
});
}
}
@@ -909,15 +1002,53 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
filesList.Add(new DatabaseFile()
{
Id = file.ID,
Name = file.Name,
Type = FileType.Log.ToString(),
Path = Path.GetDirectoryName(file.FileName),
FileGroup = string.Empty
Type = displayFileTypes[FileType.Log],
Path = Utility.DatabaseUtils.ConvertToLocalMachinePath(Path.GetDirectoryName(file.FileName)),
FileGroup = SR.prototype_file_noFileGroup,
FileNameWithExtension = Path.GetFileName(file.FileName),
SizeInMb = ByteConverter.ConvertKbtoMb(file.Size),
AutoFileGrowth = file.GrowthType == FileGrowthType.Percent ? file.Growth : ByteConverter.ConvertKbtoMb(file.Growth),
AutoFileGrowthType = file.GrowthType,
MaxSizeLimitInMb = file.MaxSize == -1 ? file.MaxSize : ByteConverter.ConvertKbtoMb(file.MaxSize),
IsAutoGrowthEnabled = file.GrowthType != FileGrowthType.None
});
}
return filesList.ToArray();
}
/// <summary>
/// Get the file group names from the database fileGroup
/// </summary>
/// <param name="database">smo database prototype</param>
/// <param name="databaseViewInfo">database view info object</param>
private void GetFileGroupNames(Database database, DatabaseViewInfo databaseViewInfo)
{
var rowDataGroups = new List<string>();
var fileStreamDataGroups = new List<string>();
foreach (FileGroup fileGroup in database.FileGroups)
{
if (fileGroup.FileGroupType == FileGroupType.FileStreamDataFileGroup || fileGroup.FileGroupType == FileGroupType.MemoryOptimizedDataFileGroup)
{
fileStreamDataGroups.Add(fileGroup.Name);
}
else
{
rowDataGroups.Add(fileGroup.Name);
}
}
// If no fileStream groups available
if (fileStreamDataGroups.Count == 0)
{
fileStreamDataGroups.Add(SR.prototype_file_noApplicableFileGroup);
}
databaseViewInfo.RowDataFileGroupsOptions = rowDataGroups.ToArray();
databaseViewInfo.FileStreamFileGroupsOptions = fileStreamDataGroups.ToArray();
}
/// <summary>
/// Get supported database compatibility levels for this Azure server.
/// </summary>

View File

@@ -3,6 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlServer.Management.Smo;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
/// <summary>
@@ -40,6 +42,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public bool EncryptionEnabled { get; set; }
public string? RestrictAccess { get; set; }
public DatabaseScopedConfigurationsInfo[]? DatabaseScopedConfigurations { get; set; }
public bool? IsFilesTabSupported { get; set; }
public DatabaseFile[] Files { get; set; }
}
public class DatabaseScopedConfigurationsInfo
@@ -49,4 +53,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string ValueForPrimary { get; set; }
public string ValueForSecondary { get; set; }
}
public class DatabaseFile
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Path { get; set; }
public string FileGroup { get; set; }
public string FileNameWithExtension { get; set; }
public double SizeInMb { get; set; }
public bool IsAutoGrowthEnabled { get; set; }
public double AutoFileGrowth { get; set; }
public FileGrowthType AutoFileGrowthType { get; set; }
public double MaxSizeLimitInMb { get; set; }
}
}

View File

@@ -14,7 +14,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public OptionsCollection CompatibilityLevels { get; set; }
public OptionsCollection ContainmentTypes { get; set; }
public OptionsCollection RecoveryModels { get; set; }
public DatabaseFile[] Files { get; set; }
public bool IsAzureDB { get; set; }
public bool IsManagedInstance { get; set; }
@@ -28,6 +27,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string[] DscOnOffOptions { get; set; }
public string[] DscElevateOptions { get; set; }
public string[] DscEnableDisableOptions { get; set; }
public string[] RowDataFileGroupsOptions { get; set; }
public string[] FileStreamFileGroupsOptions { get; set; }
public string[] FileTypesOptions { get; set; }
}
public class AzureEditionDetails
@@ -36,14 +38,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public OptionsCollection EditionOptions { get; set; }
}
public class DatabaseFile
{
public string Name { get; set; }
public string Type { get; set; }
public string Path { get; set; }
public string FileGroup { get; set; }
}
public class OptionsCollection {
public string[] Options { get; set; }
public int DefaultValueIndex { get; set; }

View File

@@ -112,7 +112,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
return false;
}
}
return true;
return true;
}
finally
{
@@ -346,5 +346,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
return new string(nameChars);
}
private static readonly HashSet<char> illegalFilenameCharacters = new HashSet<char>(new char[] { '\\', '/', ':', '*', '?', '"', '<', '>', '|' });
/// <summary>
/// Converts path to local path with DirectorySeparatorChar
/// </summary>
/// <param name="filePath"></param>
/// <returns>path with local directory separator</returns>
public static string ConvertToLocalMachinePath(string filePath)
{
string pathSeparator = Path.DirectorySeparatorChar.ToString();
string localPath = filePath.Replace("/", pathSeparator);
localPath = localPath.Replace("\\", pathSeparator);
return localPath;
}
}
}