Skip to content

Commit 3190276

Browse files
authored
8 feature request add support for table variable declarations (#9)
* Add table varible declaration support * Remove 'End Of Parameter Declaration' marker setting, as it is no longer needed * Update readme * Update to version 1.5: Added support for table variable declarations
1 parent 5751398 commit 3190276

File tree

7 files changed

+48
-86
lines changed

7 files changed

+48
-86
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,13 @@ The code generated for this sql with 'Generate Poco' turned on would be the foll
9797

9898
You can turn on this feature at sql file level by using the properties window of the file, or change the default for new files via 'Tools/Options/SqlQueryTools'.
9999

100+
### Table variable declaration support
100101

102+
Table varable declaration support was added in version 1.5.
103+
Before this version the code generation failed with the error: Variable @VariableName is used in the query, but it is not defined in the 'Parameter Declaration'.
101104

105+
To make this possible the parsing of the sql code has been rewritten. The extra advantage is that we don't need the 'End Of Parameter Declaration' marker line anymore.
106+
So whem you create a new Sql Tools file it is no longer added. In existing files the line is ignored as any other comment line.
102107

103108
### License
104109

src/SqlQueryTools/Commands/AddSqlFileCommand.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)
6464

6565
var contentBuilder = new StringBuilder();
6666

67-
contentBuilder.AppendLine("--Add your declarations here.");
68-
contentBuilder.AppendLine();
69-
contentBuilder.AppendLine(options.EndOfParameterDeclarationMarker);
70-
contentBuilder.AppendLine();
7167
contentBuilder.AppendLine("--Add your query here.");
7268

7369
File.WriteAllText(newFileFullName, contentBuilder.ToString());

src/SqlQueryTools/FileHandlers/SqlSaveHandler.cs

Lines changed: 38 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -75,98 +75,64 @@ private async Task GenerateSqlConstStringAsync(string inputFilePath)
7575

7676
var sqlFileContent = doc.TextBuffer.CurrentSnapshot.GetText();
7777
var parser = new TSql160Parser(false);
78-
var sqlParserTokens = parser.GetTokenStream(new StringReader(sqlFileContent), out var sqlParserErrors);
79-
if (sqlParserErrors.Count > 0)
78+
var sqlStatementList = parser.ParseStatementList(new StringReader(sqlFileContent), out var sqlParserStatementsErrors);
79+
if (sqlParserStatementsErrors.Count > 0)
8080
{
8181
await outputPane.WriteLineAsync("\tCode could not be generated due to the following sql parse errors:");
82-
foreach (var error in sqlParserErrors)
82+
var counter = 0;
83+
foreach (var error in sqlParserStatementsErrors)
8384
{
84-
await outputPane.WriteLineAsync($"\t\t{error.Message} (line={error.Line}, column={error.Column})");
85+
counter++;
86+
await outputPane.WriteLineAsync($"\t\t{counter}.) {error.Message} (line={error.Line}, column={error.Column})");
8587
}
8688
return;
8789
}
8890

89-
var hasDeclarationSection = sqlParserTokens.Any(x => x.TokenType == TSqlTokenType.SingleLineComment && x.Text == options.EndOfParameterDeclarationMarker);
90-
var endOfParameterDeclarationMarkerFound = false;
91-
var declaredParameters = new Dictionary<string,string>();
92-
var foundParameterDeclaration = String.Empty;
91+
var parameterDeclarationList = new List<(string Name, string Type)>();
9392
var sqlCodeBuilder = new StringBuilder();
94-
var whiteSpaceBuffer = new StringBuilder();
95-
foreach (var token in sqlParserTokens)
93+
for (int i = 0; i < sqlStatementList.Statements.Count; i++)
9694
{
97-
if (hasDeclarationSection && endOfParameterDeclarationMarkerFound == false)
95+
if (sqlStatementList.Statements[i] is DeclareVariableStatement variableStatement)
9896
{
99-
if (token.TokenType == TSqlTokenType.SingleLineComment && token.Text == options.EndOfParameterDeclarationMarker)
97+
foreach (var declaration in variableStatement.Declarations)
10098
{
101-
endOfParameterDeclarationMarkerFound = true;
102-
continue;
103-
}
104-
105-
if (token.TokenType == TSqlTokenType.Variable)
106-
{
107-
foundParameterDeclaration = token.Text;
108-
declaredParameters.Add(foundParameterDeclaration, string.Empty);
109-
continue;
110-
}
111-
112-
if (token.TokenType == TSqlTokenType.Identifier && !string.IsNullOrEmpty(foundParameterDeclaration))
113-
{
114-
declaredParameters[foundParameterDeclaration] = token.Text;
115-
foundParameterDeclaration = string.Empty;
116-
}
117-
}
118-
else
119-
{
120-
if (token.TokenType == TSqlTokenType.SingleLineComment)
121-
{
122-
continue;
123-
}
124-
125-
if (token.TokenType == TSqlTokenType.MultilineComment)
126-
{
127-
continue;
128-
}
129-
130-
if (token.TokenType == TSqlTokenType.WhiteSpace)
131-
{
132-
if (sqlCodeBuilder.Length > 0)
99+
var name = declaration.VariableName.Value;
100+
var type = string.Empty;
101+
for ( var j = declaration.DataType.FirstTokenIndex; j <= declaration.DataType.LastTokenIndex; j++)
133102
{
134-
whiteSpaceBuffer.Append(token.Text);
103+
type += declaration.DataType.ScriptTokenStream[j].Text;
135104
}
136-
continue;
137-
}
138-
139-
if (token.TokenType == TSqlTokenType.EndOfFile)
140-
{
141-
continue;
105+
parameterDeclarationList.Add((name, type));
142106
}
107+
continue;
108+
}
143109

144-
if (token.TokenType == TSqlTokenType.Variable)
145-
{
146-
if (!declaredParameters.ContainsKey(token.Text))
147-
{
148-
await outputPane.WriteLineAsync($"\tVariable {token.Text} is used in the query, but it is not defined in the 'Parameter Declarat");
149-
return;
150-
}
151-
}
110+
if (sqlStatementList.Statements[i] is DeclareTableVariableStatement tableVariableStatement)
111+
{
112+
var name = tableVariableStatement.Body.VariableName.Value;
113+
parameterDeclarationList.Add((name, null));
114+
}
152115

153-
if (whiteSpaceBuffer.Length > 0)
154-
{
155-
sqlCodeBuilder.Append(whiteSpaceBuffer.ToString());
156-
whiteSpaceBuffer.Clear();
157-
}
116+
for (int j = sqlStatementList.Statements[i].FirstTokenIndex; j <= sqlStatementList.Statements[i].LastTokenIndex; j++)
117+
{
118+
sqlCodeBuilder.Append(sqlStatementList.Statements[i].ScriptTokenStream[j].Text);
119+
}
158120

159-
sqlCodeBuilder.Append(token.Text);
121+
if ((i + 1) < sqlStatementList.Statements.Count)
122+
{
123+
sqlCodeBuilder.AppendLine();
124+
sqlCodeBuilder.AppendLine();
160125
}
161126
}
162127

163-
var sqlCode = sqlCodeBuilder.ToString();
164-
if (string.IsNullOrWhiteSpace(sqlCode))
128+
if (sqlCodeBuilder.Length <= 0)
165129
{
166130
await outputPane.WriteLineAsync("\tCode could not be generated due to no sql code found.");
167131
return;
168132
}
169133

134+
var sqlCode = sqlCodeBuilder.ToString();
135+
170136
List<SpDescribeFirstResultSetResult> queryMetaData;
171137
try
172138
{
@@ -177,19 +143,20 @@ private async Task GenerateSqlConstStringAsync(string inputFilePath)
177143
{
178144
var queryBuilder = new StringBuilder();
179145
queryBuilder.AppendLine($"DECLARE @sql NVARCHAR(MAX) = '{sqlCode.Replace("'", "''")}';");
180-
queryBuilder.AppendLine($"DECLARE @params NVARCHAR(MAX) = '{string.Join(", ", declaredParameters.Select(x => $"{x.Key} {x.Value}"))}';");
146+
queryBuilder.AppendLine($"DECLARE @params NVARCHAR(MAX) = '{string.Join(", ", parameterDeclarationList.Where(x => x.Type != null).Select(x => $"{x.Name} {x.Type}"))}';");
181147
queryBuilder.AppendLine("EXEC sp_describe_first_result_set @sql, @params;");
182148
queryMetaData = conn.Query<SpDescribeFirstResultSetResult>(queryBuilder.ToString()).ToList();
183149
}
184150
catch (SqlException ex)
185151
{
186152
await outputPane.WriteLineAsync("\tCode could not be generated due to the following sql parse errors:");
187-
153+
var counter = 0;
188154
foreach (SqlError sqlError in ex.Errors)
189155
{
190156
if (sqlError.Number == 11529 || sqlError.Number == 11501) continue;
191157

192-
await outputPane.WriteLineAsync($"\t\t{sqlError.Message}");
158+
counter++;
159+
await outputPane.WriteLineAsync($"\t\t{counter}.) {sqlError.Message}");
193160
}
194161
return;
195162
}
@@ -238,7 +205,7 @@ private async Task GenerateSqlConstStringAsync(string inputFilePath)
238205
var generateParameterNames = await inputPhysicalFile.GetGenerateParameterNamesAsync(options.GenerateParameterNames);
239206
if (generateParameterNames)
240207
{
241-
foreach (var name in declaredParameters.Keys)
208+
foreach (var name in parameterDeclarationList.Where(x => x.Type != null).Select(x => x.Name))
242209
{
243210
contentBuilder.AppendLine();
244211
contentBuilder.AppendLine($"\t\tpublic const string {name} = @\"{name}\";");

src/SqlQueryTools/Options/GeneralOptions.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@ internal class GeneralOptions : BaseOptionModel<GeneralOptions>
1010
[DefaultValue(".sqt.sql")]
1111
public string SqlFileSuffix { get; set; } = ".sqt.sql";
1212

13-
[Category("Sql File")]
14-
[DisplayName("End of parameter declaration marker")]
15-
[Description("Marker used in sql files to indicate the end of the parameter declaration.")]
16-
[DefaultValue("---------- End Of Parameter Declaration ----------")]
17-
public string EndOfParameterDeclarationMarker { get; set; } = "---------- End Of Parameter Declaration ----------";
18-
1913
[Category("Sql File")]
2014
[DisplayName("Default generate parameter names")]
2115
[Description("This default is used when a new sql file is created. It marks that the parameter name fields should be generated for this sql file.")]

src/SqlQueryTools/SqlQueryTools.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,16 @@
121121
</ItemGroup>
122122
<ItemGroup>
123123
<PackageReference Include="Community.VisualStudio.Toolkit.17">
124-
<Version>17.0.482</Version>
124+
<Version>17.0.503</Version>
125125
</PackageReference>
126126
<PackageReference Include="Community.VisualStudio.VSCT" Version="16.0.29.6" PrivateAssets="all" />
127127
<PackageReference Include="Dapper">
128128
<Version>2.0.123</Version>
129129
</PackageReference>
130130
<PackageReference Include="Microsoft.SqlServer.DacFx">
131-
<Version>160.6296.0</Version>
131+
<Version>162.0.52</Version>
132132
</PackageReference>
133-
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.4.2118">
133+
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.6.2164">
134134
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
135135
<PrivateAssets>all</PrivateAssets>
136136
</PackageReference>

src/SqlQueryTools/source.extension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal sealed partial class Vsix
1111
public const string Name = "SqlQueryTools";
1212
public const string Description = @"Generate class with string based on Sql file content.";
1313
public const string Language = "en-US";
14-
public const string Version = "1.3";
14+
public const string Version = "1.5";
1515
public const string Author = "Gert Marginet";
1616
public const string Tags = "";
1717
}

src/SqlQueryTools/source.extension.vsixmanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
33
<Metadata>
4-
<Identity Id="SqlQueryTools.46119220-B112-4974-BF62-BA76F5548B13" Version="1.4" Language="en-US" Publisher="Gert Marginet" />
4+
<Identity Id="SqlQueryTools.46119220-B112-4974-BF62-BA76F5548B13" Version="1.5" Language="en-US" Publisher="Gert Marginet" />
55
<DisplayName>SqlQueryTools</DisplayName>
66
<Description xml:space="preserve">Generate class with string based on Sql file content.</Description>
77
<MoreInfo>http://github.com/gmarginet/SqlQueryTools</MoreInfo>

0 commit comments

Comments
 (0)