diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs index 43a9c23b62..c94c60a7ae 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/AgentService.cs @@ -131,7 +131,7 @@ public void InitializeService(ServiceHost serviceHost) this.ServiceHost.SetRequestHandler(UpdateAgentNotebookRequest.Type, HandleUpdateAgentNotebookRequest); this.ServiceHost.SetRequestHandler(UpdateAgentNotebookRunPinRequest.Type, HandleUpdateAgentNotebookRunPinRequest); this.ServiceHost.SetRequestHandler(UpdateAgentNotebookRunNameRequest.Type, HandleUpdateAgentNotebookRunNameRequest); - + this.ServiceHost.SetRequestHandler(DeleteNotebookMaterializedRequest.Type, HandleDeleteNotebookMaterializedRequest); serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) => { @@ -1265,7 +1265,7 @@ internal async Task HandleAgentNotebooksRequest(AgentNotebooksParams parameters, parameters.OwnerUri, out connInfo); - result = GetAgentNotebookHistories( + result = await GetAgentNotebookHistories( connInfo, parameters.JobId, parameters.JobName, @@ -1320,7 +1320,7 @@ internal async Task HandleAgentNotebookTemplateRequest(AgentNotebookTemplatePara ConnectionServiceInstance.TryFindConnection( parameters.OwnerUri, out connInfo); - result.NotebookTemplate = AgentNotebookHelper.GetTemplateNotebook(connInfo, parameters.JobId, parameters.TargetDatabase).Result; + result.NotebookTemplate = await AgentNotebookHelper.GetTemplateNotebook(connInfo, parameters.JobId, parameters.TargetDatabase); result.Success = true; } catch (Exception e) @@ -1426,7 +1426,7 @@ internal async Task HandleUpdateAgentNotebookRunNameRequest(UpdateAgentNotebookR // Calling update helper function await AgentNotebookHelper.UpdateMaterializedNotebookName( connInfo, - parameters.MaterializedId, + parameters.agentNotebookHistory, parameters.TargetDatabase, parameters.MaterializedNotebookName); result.Success = true; @@ -1455,7 +1455,7 @@ internal async Task HandleUpdateAgentNotebookRunPinRequest(UpdateAgentNotebookRu // Calling update helper function await AgentNotebookHelper.UpdateMaterializedNotebookPin( connInfo, - parameters.MaterializedId, + parameters.agentNotebookHistory, parameters.TargetDatabase, parameters.MaterializedNotebookPin); result.Success = true; @@ -1470,7 +1470,36 @@ internal async Task HandleUpdateAgentNotebookRunPinRequest(UpdateAgentNotebookRu }); } - public AgentNotebookHistoryResult GetAgentNotebookHistories( + internal async Task HandleDeleteNotebookMaterializedRequest(DeleteNotebookMaterializedParams parameters, RequestContext requestContext) + { + await Task.Run(async () => + { + var result = new ResultStatus(); + try + { + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + parameters.OwnerUri, + out connInfo); + // Calling update helper function + await AgentNotebookHelper.DeleteMaterializedNotebook( + connInfo, + parameters.agentNotebookHistory, + parameters.TargetDatabase); + result.Success = true; + } + catch (Exception e) + { + result.Success = false; + result.ErrorMessage = e.ToString(); + + } + await requestContext.SendResult(result); + }); + } + + public async Task GetAgentNotebookHistories + ( ConnectionInfo connInfo, string jobId, string jobName, @@ -1519,7 +1548,7 @@ string targetDatabase var jobHistories = AgentUtilities.ConvertToAgentNotebookHistoryInfo(logEntries, job, steps); // fetching notebook part of histories Dictionary notebookHistoriesDict = new Dictionary(); - DataTable materializedNotebookTable = AgentNotebookHelper.GetAgentNotebookHistories(connInfo, jobId, targetDatabase).Result; + DataTable materializedNotebookTable = await AgentNotebookHelper.GetAgentNotebookHistories(connInfo, jobId, targetDatabase); foreach (DataRow materializedNotebookRow in materializedNotebookTable.Rows) { string materializedRunDateTime = materializedNotebookRow["run_date"].ToString() + materializedNotebookRow["run_time"].ToString(); @@ -1537,8 +1566,14 @@ string targetDatabase notebookHistory.MaterializedNotebookErrorInfo = notebookHistoriesDict[jobRuntime]["notebook_error"] as string; notebookHistory.MaterializedNotebookName = notebookHistoriesDict[jobRuntime]["notebook_name"] as string; notebookHistory.MaterializedNotebookPin = (bool)notebookHistoriesDict[jobRuntime]["pin"]; + notebookHistory.MaterializedNotebookDeleted = (bool)notebookHistoriesDict[jobRuntime]["is_deleted"]; + } + if (notebookHistory.MaterializedNotebookDeleted) + { + continue; } notebookHistories.Add(notebookHistory); + } result.Histories = notebookHistories.ToArray(); tlog.CloseReader(); diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentJobHistoryInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentJobHistoryInfo.cs index 637193a722..0173dda3ab 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentJobHistoryInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentJobHistoryInfo.cs @@ -69,5 +69,6 @@ public class AgentNotebookHistoryInfo : AgentJobHistoryInfo public string MaterializedNotebookName { get; set; } public int MaterializedNotebookErrorFlag { get; set; } public string MaterializedNotebookErrorInfo { get; set; } + public bool MaterializedNotebookDeleted { get; set; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentNotebookRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentNotebookRequest.cs index b939c14945..cf0fb02503 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentNotebookRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/Contracts/AgentNotebookRequest.cs @@ -219,7 +219,7 @@ public static readonly public class UpdateAgentNotebookRunNameParams : TaskRequestDetails { public string OwnerUri { get; set; } - public int MaterializedId { get; set; } + public AgentNotebookHistoryInfo agentNotebookHistory { get; set; } public string MaterializedNotebookName { get; set; } public string TargetDatabase { get; set; } @@ -241,7 +241,7 @@ public static readonly public class UpdateAgentNotebookRunPinParams : TaskRequestDetails { public string OwnerUri { get; set; } - public string MaterializedId { get; set; } + public AgentNotebookHistoryInfo agentNotebookHistory{ get; set; } public bool MaterializedNotebookPin { get; set; } public string TargetDatabase { get; set; } @@ -256,4 +256,32 @@ public static readonly RequestType Type = RequestType.Create("agent/updatenotebookpin"); } + + /// + /// SQL Agent Notebook materialized params + /// + public class DeleteNotebookMaterializedParams : TaskRequestDetails + { + public string OwnerUri { get; set; } + public string TargetDatabase { get; set; } + public AgentNotebookHistoryInfo agentNotebookHistory { get; set; } + } + + /// + /// SQL Agent Notebook materialized result + /// + public class DeleteNotebookMaterializedResult : ResultStatus + { + public string NotebookMaterialized { get; set; } + } + + /// + /// SQL Agent Notebook materialized request type + /// + public class DeleteNotebookMaterializedRequest + { + public static readonly + RequestType Type = + RequestType.Create("agent/deletenotebookmaterialized"); + } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentNotebookHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentNotebookHelper.cs index 4420a50aef..30cb02e760 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentNotebookHelper.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Agent/Jobs/AgentNotebookHelper.cs @@ -190,7 +190,7 @@ INNER JOIN ConfigAction.Drop, runType); - if(!deleteJobResult.Item1) + if (!deleteJobResult.Item1) { throw new Exception(deleteJobResult.Item2); } @@ -200,7 +200,7 @@ INNER JOIN notebook.JobId, notebook.TargetDatabase); - + } internal static async Task UpdateNotebook( @@ -228,8 +228,8 @@ INNER JOIN notebook, ConfigAction.Update, runType); - - if(!updateJobResult.Item1) + + if (!updateJobResult.Item1) { throw new Exception(updateJobResult.Item2); } @@ -265,7 +265,8 @@ INNER JOIN run_date, notebook_error, pin, - notebook_name + notebook_name, + is_deleted FROM notebooks.nb_materialized WHERE JOB_ID = @jobId"; @@ -281,13 +282,6 @@ INNER JOIN return result; } - /// - /// - /// - /// - /// - /// - /// public static async Task GetMaterializedNotebook( ConnectionInfo connInfo, int materializedId, @@ -340,12 +334,6 @@ INNER JOIN return templateNotebookRows["notebook"] as string; } - /// - /// - /// - /// - /// - /// public static AgentJobStepInfo[] CreateNotebookPowerShellStep( string notebookName, string storageDatabase) @@ -438,6 +426,7 @@ last_run_notebook_error NVARCHAR(MAX) notebook NVARCHAR(MAX), notebook_error NVARCHAR(MAX), pin BIT NOT NULL DEFAULT 0, + is_deleted BIT NOT NULL DEFAULT 0, notebook_name NVARCHAR(MAX) NOT NULL default('') ) END @@ -567,50 +556,45 @@ UPDATE notebooks.nb_template targetDatabase); } - public static async Task GetTemplateFile( - ConnectionInfo connInfo, - string job_id, - string targetDatabase, - string templateFileContents) - { - string getNotebookTemplateQuery = - @" - SELECT notebook - from - notebooks.nb_template - where - job_id = @jobId; - "; - List getNotebookTemplateQueryParams = new List(); - getNotebookTemplateQueryParams.Add(new SqlParameter("job_id", getNotebookTemplateQueryParams)); - DataSet templateDataSet = await AgentNotebookHelper.ExecuteSqlQueries( - connInfo, - getNotebookTemplateQuery, - getNotebookTemplateQueryParams, - targetDatabase); - - DataTable templateDataTable = templateDataSet.Tables[0]; - DataRow templateDataRow = templateDataTable.Rows[0]; - return templateDataRow["notebook"] as string; - } - + /// + /// Changing the name of materialized notebook runs. Special case is handled where new row is + /// added for failed jobs which do not have an entry into the materialized table + /// + /// connectionInfo generated from OwnerUri + /// actual history item to be pinned + /// database on which the notebook history is stored + /// name for the materialized history + /// public static async Task UpdateMaterializedNotebookName( ConnectionInfo connInfo, - int materializedId, + AgentNotebookHistoryInfo agentNotebookHistory, string targetDatabase, string name) { string updateMaterializedNotebookNameQuery = - @" + @" + IF EXISTS + (SELECT * FROM notebooks.nb_materialized + WHERE job_id = @jobId AND run_time = @startTime AND run_date = @startDate) + BEGIN UPDATE notebooks.nb_materialized SET - notebook_name = @notebookName + notebook_name = @notebookName WHERE - materialized_id = @materializedId + job_id = @jobId AND run_time = @startTime AND run_date = @startDate + END + ELSE + BEGIN + INSERT INTO notebooks.nb_materialized (job_id, run_time, run_date, notebook, notebook_error, notebook_name) + VALUES + (@jobID, @startTime, @startDate, '', '', @notebookName) + END "; List updateMaterializedNotebookNameParams = new List(); + updateMaterializedNotebookNameParams.Add(new SqlParameter("jobID", agentNotebookHistory.JobId)); + updateMaterializedNotebookNameParams.Add(new SqlParameter("startTime", agentNotebookHistory.RunDate.ToString("HHmmss"))); + updateMaterializedNotebookNameParams.Add(new SqlParameter("startDate", agentNotebookHistory.RunDate.ToString("yyyyMMdd"))); updateMaterializedNotebookNameParams.Add(new SqlParameter("notebookName", name)); - updateMaterializedNotebookNameParams.Add(new SqlParameter("materializedId", materializedId)); await AgentNotebookHelper.ExecuteSqlQueries( connInfo, updateMaterializedNotebookNameQuery, @@ -618,28 +602,97 @@ UPDATE notebooks.nb_materialized targetDatabase); } + /// + /// Changing the pin state of materialized notebook runs. Special case is handled where new row is + /// added for failed jobs which do not have an entry into the materialized table + /// + /// connectionInfo generated from OwnerUri + /// actual history item to be pinned + /// database on which the notebook history is stored + /// pin state for the history + /// public static async Task UpdateMaterializedNotebookPin( ConnectionInfo connInfo, - string materializedId, + AgentNotebookHistoryInfo agentNotebookHistory, string targetDatabase, bool pin) { string updateMaterializedNotebookPinQuery = - @" + @" + IF EXISTS + (SELECT * FROM notebooks.nb_materialized + WHERE job_id = @jobId AND run_time = @startTime AND run_date = @startDate) + BEGIN UPDATE notebooks.nb_materialized SET - pin = @notebookPin + pin = @notebookPin WHERE - materialized_id = @materializedId + job_id = @jobId AND run_time = @startTime AND run_date = @startDate + END + ELSE + BEGIN + INSERT INTO notebooks.nb_materialized (job_id, run_time, run_date, notebook, notebook_error, pin) + VALUES + (@jobID, @startTime, @startDate, '', '', @notebookPin) + END "; List updateMaterializedNotebookPinParams = new List(); + updateMaterializedNotebookPinParams.Add(new SqlParameter("jobID", agentNotebookHistory.JobId)); + updateMaterializedNotebookPinParams.Add(new SqlParameter("startTime", agentNotebookHistory.RunDate.ToString("HHmmss"))); + updateMaterializedNotebookPinParams.Add(new SqlParameter("startDate", agentNotebookHistory.RunDate.ToString("yyyyMMdd"))); updateMaterializedNotebookPinParams.Add(new SqlParameter("notebookPin", pin)); - updateMaterializedNotebookPinParams.Add(new SqlParameter("materializedId", materializedId)); await AgentNotebookHelper.ExecuteSqlQueries( connInfo, updateMaterializedNotebookPinQuery, updateMaterializedNotebookPinParams, targetDatabase); } + + /// + /// Delete a particular run of the job. Deletion mainly including clearing out the notebook, + /// and notebook-error. The API doesn't delete the row because some notebook runs that have job + /// error in them don't have an entry in the materialized table. For keeping track of those notebook + /// runs the entry is added into the table with is_delete set to 1. + /// + /// connectionInfo generated from OwnerUri + /// Actual history item to be deleted + /// database on which the notebook history is stored + /// + public static async Task DeleteMaterializedNotebook( + ConnectionInfo connInfo, + AgentNotebookHistoryInfo agentNotebookHistory, + string targetDatabase) + { + string deleteMaterializedNotebookQuery = + @" + IF EXISTS + (SELECT * FROM notebooks.nb_materialized + WHERE job_id = @jobId AND run_time = @startTime AND run_date = @startDate) + BEGIN + UPDATE notebooks.nb_materialized + SET is_deleted = 1, + notebook = '', + notebook_error = '', + WHERE + job_id = @jobId AND run_time = @startTime AND run_date = @startDate + END + ELSE + BEGIN + INSERT INTO notebooks.nb_materialized (job_id, run_time, run_date, notebook, notebook_error, is_deleted) + VALUES + (@jobID, @startTime, @startDate, '', '', 1) + END + "; + List deleteMaterializedNotebookParams = new List(); + deleteMaterializedNotebookParams.Add(new SqlParameter("jobID", agentNotebookHistory.JobId)); + deleteMaterializedNotebookParams.Add(new SqlParameter("startTime", agentNotebookHistory.RunDate.ToString("HHmmss"))); + deleteMaterializedNotebookParams.Add(new SqlParameter("startDate", agentNotebookHistory.RunDate.ToString("yyyyMMdd"))); + deleteMaterializedNotebookParams.Add(new SqlParameter("materializedId", agentNotebookHistory.MaterializedNotebookId)); + await AgentNotebookHelper.ExecuteSqlQueries( + connInfo, + deleteMaterializedNotebookQuery, + deleteMaterializedNotebookParams, + targetDatabase); + } } } \ No newline at end of file