예제 #1
0
		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;
		}
예제 #2
0
		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;
		}
예제 #3
0
		private void DisposeDebuggerSession()
		{
			_debuggerSession?.Dispose();
			_debuggerSession = null;
		}