Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.SqlServer.TransactSql.ScriptDom;

namespace Microsoft.SqlServer.TransactSql.ScriptDom.ScriptGenerator
Expand All @@ -11,45 +12,98 @@ partial class SqlScriptGeneratorVisitor
{
public override void ExplicitVisit(SimpleCaseExpression node)
{
GenerateKeyword(TSqlTokenType.Case);
bool multiline = BeginCaseExpression();

GenerateSpaceAndFragmentIfNotNull(node.InputExpression);

foreach (SimpleWhenClause when in node.WhenClauses)
{
GenerateSpaceAndFragmentIfNotNull(when);
}
GenerateCaseBody(node.WhenClauses, node.ElseExpression, multiline);

if (node.ElseExpression != null)
{
GenerateSpaceAndKeyword(TSqlTokenType.Else);
GenerateSpaceAndFragmentIfNotNull(node.ElseExpression);
}
GenerateSpaceAndCollation(node.Collation);
}

GenerateSpaceAndKeyword(TSqlTokenType.End);
public override void ExplicitVisit(SearchedCaseExpression node)
{
bool multiline = BeginCaseExpression();

GenerateCaseBody(node.WhenClauses, node.ElseExpression, multiline);

GenerateSpaceAndCollation(node.Collation);
}

public override void ExplicitVisit(SearchedCaseExpression node)
// Writes CASE. With MultilineCaseExpression it first pushes an alignment point at the CASE
// keyword, which GenerateCaseBody pops after END, so that every line of the body starts
// from the CASE column. Without it no point is pushed, which keeps the single-line output
// unchanged.
private bool BeginCaseExpression()
{
GenerateKeyword(TSqlTokenType.Case);
bool multiline = _options.MultilineCaseExpression;

foreach (SearchedWhenClause when in node.WhenClauses)
if (multiline)
{
GenerateSpaceAndFragmentIfNotNull(when);
MarkAndPushAlignmentPoint(new AlignmentPoint());
}

if (node.ElseExpression != null)
GenerateKeyword(TSqlTokenType.Case);

return multiline;
}

private void GenerateCaseBody<TWhenClause>(IList<TWhenClause> whenClauses, ScalarExpression elseExpression, bool multiline)
where TWhenClause : WhenClause
{
foreach (TWhenClause when in whenClauses)
{
GenerateSpaceAndKeyword(TSqlTokenType.Else);
GenerateSpaceAndFragmentIfNotNull(node.ElseExpression);
GenerateCaseBodyLineStart(multiline);

// Newlines from a comment before the WHEN restore to this point, not the CASE column.
if (multiline)
{
MarkAndPushAlignmentPointKeepingNameScope(new AlignmentPoint());
}

GenerateFragmentIfNotNull(when);

if (multiline)
{
PopAlignmentPoint();
}
}

GenerateSpaceAndKeyword(TSqlTokenType.End);
if (elseExpression != null)
{
if (multiline)
{
EmitPendingCommentsOnOwnLines(NewLineAndIndent);
}

GenerateSpaceAndCollation(node.Collation);
GenerateCaseBodyLineStart(multiline);
GenerateKeyword(TSqlTokenType.Else);
GenerateSpaceAndFragmentIfNotNull(elseExpression);
}

if (multiline)
{
EmitPendingCommentsOnOwnLines(NewLineAndIndent);
NewLine();
GenerateKeyword(TSqlTokenType.End);
PopAlignmentPoint();
}
else
{
GenerateSpaceAndKeyword(TSqlTokenType.End);
}
}

private void GenerateCaseBodyLineStart(bool multiline)
{
if (multiline)
{
NewLineAndIndent();
}
else
{
GenerateSpace();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,41 @@ protected void EmitCommentsUntilNextNonTriviaToken()
}
}

/// <summary>
/// Emits the pending comments, each on a line started by <paramref name="startLine"/>.
/// </summary>
protected void EmitPendingCommentsOnOwnLines(Action startLine)
{
if (!_options.PreserveComments || _currentTokenStream == null)
{
return;
}

for (int i = _lastProcessedTokenIndex + 1; i < _currentTokenStream.Count; i++)
{
var token = _currentTokenStream[i];

if (IsCommentToken(token))
{
if (!_emittedComments.Contains(token))
{
startLine();
_writer.AddToken(new TSqlParserToken(token.TokenType, token.Text));
_emittedComments.Add(token);
_lastProcessedTokenIndex = i;
}
continue;
}

if (token.TokenType == TSqlTokenType.WhiteSpace)
{
continue;
}

break;
}
}

/// <summary>
/// Emits a trailing comment. '--' comments are deferred to the next
/// NewLine; block comments are written inline immediately.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@
<Summary>Gets or sets a boolean indicating if parameters in a nested function call tree should be written on separate lines and indented one level per call. Isolated function calls remain on one line. When false (the default), all function calls retain the existing compact layout.</Summary>
</Setting>
</SettingGroup>
<SettingGroup name="CASE expressions">
<Setting name="MultilineCaseExpression" type="bool" default="false">
<Summary>Gets or sets a boolean indicating if each WHEN clause and the ELSE of a CASE expression should be written on its own line, indented one level from the CASE keyword, with END on its own line aligned with CASE. This applies to simple and searched CASE expressions wherever they appear. When false (the default), a CASE expression is written on a single line.</Summary>
</Setting>
</SettingGroup>
<SettingGroup name="External Libraries">
<Setting name="AllowExternalLibraryPaths" type="bool" default="true">
<Summary>Gets or sets a boolean indicating if file paths can be used for external library content</Summary>
Expand Down
Loading