private async Task<StatementExecutionBatchResult> ExecuteUserStatementAsync(StatementBatchExecutionModel batchExecutionModel, bool isReferenceConstraintNavigation, CancellationToken cancellationToken) { if (batchExecutionModel.Statements == null || batchExecutionModel.Statements.Count == 0) { throw new ArgumentException("An execution batch must contain at least one statement. ", nameof(batchExecutionModel)); } _isExecuting = true; _userCommandHasCompilationErrors = false; var batchResult = new StatementExecutionBatchResult { ExecutionModel = batchExecutionModel }; var statementResults = new List<StatementExecutionResult>(); StatementExecutionResult currentStatementResult = null; try { SetOracleGlobalization(); await EnsureUserConnectionOpen(cancellationToken); await EnsureDatabaseOutput(cancellationToken); if (batchExecutionModel.GatherExecutionStatistics) { _executionStatisticsDataProvider = new SessionExecutionStatisticsDataProvider(_databaseModel.StatisticsKeys, _userSessionIdentifier.Value.SessionId); await _databaseModel.UpdateModelAsync(true, cancellationToken, _executionStatisticsDataProvider.SessionBeginExecutionStatisticsDataProvider); } _userConnection.ActionName = "User command"; foreach (var executionModel in batchExecutionModel.Statements) { currentStatementResult = new StatementExecutionResult { StatementModel = executionModel }; statementResults.Add(currentStatementResult); if (_userTransaction == null) { var isolationLevel = executionModel.Statement?.RootNode[NonTerminals.Statement, NonTerminals.SetTransactionStatement, NonTerminals.TransactionModeOrIsolationLevelOrRollbackSegment, NonTerminals.SerializableOrReadCommitted, Terminals.Serializable] != null ? IsolationLevel.Serializable : IsolationLevel.ReadCommitted; _userTransaction = _userConnection.BeginTransaction(isolationLevel); } var userCommand = InitializeUserCommand(); userCommand.CommandText = executionModel.StatementText.Replace("\r\n", "\n"); foreach (var variable in executionModel.BindVariables) { var value = await GetBindVariableValue(variable, cancellationToken); userCommand.AddSimpleParameter(variable.Name, value, variable.DataType.Name); } var resultInfoColumnHeaders = new Dictionary<ResultInfo, IReadOnlyList<ColumnHeader>>(); var statement = (OracleStatement)executionModel.Statement; var isPlSql = statement?.IsPlSql ?? false; if (isPlSql && batchExecutionModel.EnableDebug && executionModel.IsPartialStatement) { throw new InvalidOperationException("Debugging is not supported for PL/SQL fragment. "); } if (isPlSql) { currentStatementResult.ExecutedAt = DateTime.Now; if (batchExecutionModel.EnableDebug) { // TODO: Add COMPILE DEBUG _debuggerSession = new OracleDebuggerSession(this, (OracleCommand)userCommand.Clone(), batchResult); _debuggerSession.Detached += DebuggerSessionDetachedHandler; } else { currentStatementResult.AffectedRowCount = await userCommand.ExecuteNonQueryAsynchronous(cancellationToken); currentStatementResult.Duration = DateTime.Now - currentStatementResult.ExecutedAt; resultInfoColumnHeaders.AddRange(AcquireImplicitRefCursors(userCommand)); } } else { currentStatementResult.ExecutedAt = DateTime.Now; var dataReader = await userCommand.ExecuteReaderAsynchronous(CommandBehavior.Default, cancellationToken); currentStatementResult.Duration = DateTime.Now - currentStatementResult.ExecutedAt; currentStatementResult.AffectedRowCount = dataReader.RecordsAffected; var resultInfo = isReferenceConstraintNavigation ? new ResultInfo($"ReferenceConstrantResult{dataReader.GetHashCode()}", null, ResultIdentifierType.SystemGenerated) : new ResultInfo($"MainResult{dataReader.GetHashCode()}", $"Result set {_resultInfoColumnHeaders.Count + 1}", ResultIdentifierType.UserDefined); var columnHeaders = GetColumnHeadersFromReader(dataReader); if (columnHeaders.Count > 0) { _commandReaders.Add(resultInfo, new CommandReader { Reader = dataReader, Command = userCommand } ); resultInfoColumnHeaders.Add(resultInfo, columnHeaders); } } resultInfoColumnHeaders.AddRange(UpdateBindVariables(currentStatementResult.StatementModel, userCommand)); currentStatementResult.ResultInfoColumnHeaders = resultInfoColumnHeaders.AsReadOnly(); _resultInfoColumnHeaders.AddRange(resultInfoColumnHeaders); currentStatementResult.CompilationErrors = _userCommandHasCompilationErrors ? await RetrieveCompilationErrors(executionModel.ValidationModel.Statement, cancellationToken) : CompilationError.EmptyArray; currentStatementResult.SuccessfulExecutionMessage = statement == null ? OracleStatement.DefaultMessageCommandExecutedSuccessfully : statement.BuildExecutionFeedbackMessage(currentStatementResult.AffectedRowCount, _userCommandHasCompilationErrors); } } catch (OracleException exception) { if (currentStatementResult == null) { statementResults.Add( new StatementExecutionResult { StatementModel = batchExecutionModel.Statements[0], Exception = exception }); } else { currentStatementResult.Exception = exception; if (currentStatementResult.ExecutedAt != null && currentStatementResult.Duration == null) { currentStatementResult.Duration = DateTime.Now - currentStatementResult.ExecutedAt; } } var executionException = new StatementExecutionException(batchResult, exception); var isConnectionTerminated = TryHandleConnectionTerminatedError(exception); if (isConnectionTerminated) { throw executionException; } if (exception.Number == (int)OracleErrorCode.UserInvokedCancellation) { return batchResult; } if (currentStatementResult != null) { currentStatementResult.ErrorPosition = await GetSyntaxErrorIndex(currentStatementResult.StatementModel.StatementText, cancellationToken); } throw executionException; } finally { batchResult.StatementResults = statementResults.AsReadOnly(); try { if (_userConnection.State == ConnectionState.Open && !batchExecutionModel.EnableDebug && !cancellationToken.IsCancellationRequested) { await FinalizeBatchExecution(batchResult, cancellationToken); } } finally { _isExecuting = false; } } return batchResult; }
private void DebuggerSessionDetachedHandler(object sender, EventArgs args) { var statementResult = _debuggerSession.ExecutionResult.StatementResults[0]; var resultInfoColumnHeaders = new Dictionary<ResultInfo, IReadOnlyList<ColumnHeader>>(); resultInfoColumnHeaders.AddRange(AcquireImplicitRefCursors(_debuggerSession.DebuggedCommand)); resultInfoColumnHeaders.AddRange(UpdateBindVariables(statementResult.StatementModel, _debuggerSession.DebuggedCommand)); _resultInfoColumnHeaders.AddRange(resultInfoColumnHeaders); statementResult.ResultInfoColumnHeaders = resultInfoColumnHeaders.AsReadOnly(); _debuggerSession.Detached -= DebuggerSessionDetachedHandler; _debuggerSession.Dispose(); _debuggerSession = null; }
private void DisposeDebuggerSession() { _debuggerSession?.Dispose(); _debuggerSession = null; }