Skip to content

Commit

Permalink
Merge pull request #99 from bruce-dunwiddie/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
bruce-dunwiddie authored Jun 27, 2022
2 parents 64d3aab + ceda5cf commit 724c330
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,78 @@ internal class TSQLValueAsTypeExpressionParser
{
public TSQLArgumentList Parse(ITSQLTokenizer tokenizer)
{
List<TSQLToken> tokens = new List<TSQLToken>();
TSQLValueAsTypeExpression argument = new TSQLValueAsTypeExpression();

// need to do this before starting the argument loop
// so we can handle an empty argument list of just whitespace
// and comments
TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
tokens);

TSQLValueAsTypeExpression argument = new TSQLValueAsTypeExpression();
argument);

TSQLExpression expression = new TSQLValueExpressionParser().Parse(tokenizer);

argument.Expression = expression;

tokens.AddRange(expression.Tokens);
argument.Tokens.AddRange(expression.Tokens);

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
tokens);
argument);

if (!tokenizer.Current.IsKeyword(TSQLKeywords.AS))
{
throw new InvalidOperationException("AS expected.");
}

tokens.Add(tokenizer.Current);
argument.Tokens.Add(tokenizer.Current);

TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace(
tokenizer,
tokens);
argument.Tokens);

argument.DataType = tokenizer.Current.AsIdentifier;
List<TSQLToken> dataTypeTokens = new List<TSQLToken>();

tokens.Add(tokenizer.Current);
dataTypeTokens.Add(tokenizer.Current);

// reading until closing paren
TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace(
tokenizer,
tokens);
int nestedLevel = 0;

while (
tokenizer.MoveNext() &&
!tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) &&
!(
nestedLevel == 0 &&
tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)
))
{
if (tokenizer.Current.Type == TSQLTokenType.Character)
{
dataTypeTokens.Add(tokenizer.Current);

TSQLCharacters character = tokenizer.Current.AsCharacter.Character;

if (character == TSQLCharacters.OpenParentheses)
{
nestedLevel++;
}
else if (character == TSQLCharacters.CloseParentheses)
{
nestedLevel--;
}
}
else
{
dataTypeTokens.Add(tokenizer.Current);
}
}

argument.DataType = String.Join("", dataTypeTokens.Select(t => t.Text)).TrimEnd();
argument.Tokens.AddRange(dataTypeTokens);

TSQLArgumentList argList = new TSQLArgumentList(
new List<TSQLExpression> { argument });

argList.Tokens.AddRange(tokens);
argList.Tokens.AddRange(argument.Tokens);

return argList;
}
Expand Down
8 changes: 8 additions & 0 deletions TSQL_Parser/TSQL_Parser/Expressions/TSQLExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,13 @@ public TSQLVariableAssignmentExpression AsVariableAssignment
return this as TSQLVariableAssignmentExpression;
}
}

public TSQLValueAsTypeExpression AsValueAsType
{
get
{
return this as TSQLValueAsTypeExpression;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public override TSQLExpressionType Type

public TSQLExpression Expression { get; internal set; }

public TSQLIdentifier DataType { get; internal set; }
public string DataType { get; internal set; }
}
}
4 changes: 2 additions & 2 deletions TSQL_Parser/TSQL_Parser/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.2.1.0")]
[assembly: AssemblyFileVersion("2.2.1.0")]
[assembly: AssemblyVersion("2.2.2.0")]
[assembly: AssemblyFileVersion("2.2.2.0")]

[assembly: InternalsVisibleTo("Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100793625650b945744f8a2c57bc75da89cd4d2c551636aa180c3020b7a15b815c10e983e83c312eb02f131c6fcf18aaffd6c8d9af6c4353c91ca0e9206b0fb8fb7805fc07b510a47ff40705ae56977ae8893e2d247d166aa400926582840e8a5602df055762bc3479dd14c9621a77946b6e6b0a00a77204c78fb52c65121bd75ba")]
4 changes: 2 additions & 2 deletions TSQL_Parser/TSQL_Parser/Push.bat
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
nuget SetApiKey %NUGET_KEY%
nuget push TSQL.Parser.2.2.1.snupkg -Source https://api.nuget.org/v3/index.json
nuget push TSQL.Parser.2.2.1.nupkg -Source https://api.nuget.org/v3/index.json
nuget push TSQL.Parser.2.2.2.snupkg -Source https://api.nuget.org/v3/index.json
nuget push TSQL.Parser.2.2.2.nupkg -Source https://api.nuget.org/v3/index.json
pause
6 changes: 3 additions & 3 deletions TSQL_Parser/TSQL_Parser/TSQL_Parser.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@
<Compile Include="Statements\TSQLUpdateStatement.cs" />
<Compile Include="Tokens\Parsers\TSQLTokenFactory.cs" />
<Compile Include="Tokens\Parsers\TSQLTokenParserHelper.cs" />
<Compile Include="Tokens\TSQLIncompleteCommentToken.cs" />
<Compile Include="Tokens\TSQLIncompleteIdentifierToken.cs" />
<Compile Include="Tokens\TSQLIncompleteStringToken.cs" />
<Compile Include="Tokens\TSQLIncompleteComment.cs" />
<Compile Include="Tokens\TSQLIncompleteIdentifier.cs" />
<Compile Include="Tokens\TSQLIncompleteString.cs" />
<Compile Include="Tokens\TSQLIncompleteToken.cs" />
<Compile Include="Tokens\TSQLSystemColumnIdentifier.cs" />
<Compile Include="Tokens\TSQLSystemIdentifier.cs" />
Expand Down
4 changes: 2 additions & 2 deletions TSQL_Parser/TSQL_Parser/TSQL_Parser.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
<package>
<metadata>
<id>TSQL.Parser</id>
<version>2.2.1</version>
<version>2.2.2</version>
<title>TSQL.Parser</title>
<authors>Bruce Dunwiddie</authors>
<owners>shriop</owners>
<license type="expression">Apache-2.0</license>
<projectUrl>https://github.com/bruce-dunwiddie/tsql-parser</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Library for Parsing SQL Server T-SQL Scripts</description>
<releaseNotes>Fixed simple single column SELECT parsing.</releaseNotes>
<releaseNotes>Fixed parsing of CAST function arguments when data type specification includes parentheses.</releaseNotes>
<copyright>Copyright © 2022</copyright>
<tags>sql parser sql-server tsql</tags>
</metadata>
Expand Down
6 changes: 3 additions & 3 deletions TSQL_Parser/TSQL_Parser/TSQL_Parser_NetStandard.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>TSQL_Parser</AssemblyName>
<RootNamespace>TSQL_Parser</RootNamespace>
<Version>2.2.1.0</Version>
<AssemblyVersion>2.2.1.0</AssemblyVersion>
<FileVersion>2.2.1.0</FileVersion>
<Version>2.2.2.0</Version>
<AssemblyVersion>2.2.2.0</AssemblyVersion>
<FileVersion>2.2.2.0</FileVersion>
<Description>Library for Parsing SQL Server TSQL Scripts</Description>
<Copyright>Copyright © 2022</Copyright>
<Company />
Expand Down
8 changes: 4 additions & 4 deletions TSQL_Parser/TSQL_Parser/Tokens/Parsers/TSQLTokenFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public TSQLToken Parse(
else
{
return
new TSQLIncompleteCommentToken(
new TSQLIncompleteComment(
startPosition,
tokenValue);
}
Expand All @@ -80,7 +80,7 @@ public TSQLToken Parse(
else
{
return
new TSQLIncompleteStringToken(
new TSQLIncompleteString(
startPosition,
tokenValue);
}
Expand All @@ -100,7 +100,7 @@ public TSQLToken Parse(
else
{
return
new TSQLIncompleteStringToken(
new TSQLIncompleteString(
startPosition,
tokenValue);
}
Expand Down Expand Up @@ -211,7 +211,7 @@ public TSQLToken Parse(
))
{
return
new TSQLIncompleteIdentifierToken(
new TSQLIncompleteIdentifier(
startPosition,
tokenValue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace TSQL.Tokens
{
public class TSQLIncompleteCommentToken : TSQLIncompleteToken
public class TSQLIncompleteComment : TSQLIncompleteToken
{
internal TSQLIncompleteCommentToken(
internal TSQLIncompleteComment(
int beginPosition,
string text) :
base(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace TSQL.Tokens
{
public class TSQLIncompleteIdentifierToken : TSQLIncompleteToken
public class TSQLIncompleteIdentifier : TSQLIncompleteToken
{
internal TSQLIncompleteIdentifierToken(
internal TSQLIncompleteIdentifier(
int beginPosition,
string text) :
base(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace TSQL.Tokens
{
public class TSQLIncompleteStringToken : TSQLIncompleteToken
public class TSQLIncompleteString : TSQLIncompleteToken
{
internal TSQLIncompleteStringToken(
internal TSQLIncompleteString(
int beginPosition,
string text) :
base(
Expand Down
71 changes: 51 additions & 20 deletions TSQL_Parser/Tests/Statements/SelectStatementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -750,19 +750,9 @@ public void SelectStatement_system_user_Regression()
{
// regression test for https://github.com/bruce-dunwiddie/tsql-parser/issues/93
List<TSQLStatement> statements = TSQLStatementReader.ParseStatements(
//@"SELECT system_user;",
@"SELECT system_user;",
includeWhitespace: false);

// System.NullReferenceException
// this shouldn't happen even if only because it encountered the end of the string

// system_user is a system property, not a function
// is it trying to parse arguments?

// should system properties be split out from system functions?
// what should each be named?

Assert.AreEqual(1, statements.Count);
TSQLSelectStatement select = statements.Single().AsSelect;
Assert.AreEqual(3, select.Tokens.Count);
Expand All @@ -772,25 +762,66 @@ public void SelectStatement_system_user_Regression()
[Test]
public void SelectStatement_system_user_Regression_without_semicolon()
{
// regression test for https://github.com/bruce-dunwiddie/tsql-parser/issues/93
List<TSQLStatement> statements = TSQLStatementReader.ParseStatements(
//@"SELECT system_user;",
@"SELECT system_user",
includeWhitespace: false);

// System.NullReferenceException
// this shouldn't happen even if only because it encountered the end of the string
Assert.AreEqual(1, statements.Count);
TSQLSelectStatement select = statements.Single().AsSelect;
Assert.AreEqual(2, select.Tokens.Count);
Assert.AreEqual("system_user", select.Select.Columns[0].Expression.AsColumn.Column.Name);
}

// system_user is a system property, not a function
// is it trying to parse arguments?
[Test]
public void SelectStatement_CAST_argument_parsing()
{
// regression test for https://github.com/bruce-dunwiddie/tsql-parser/issues/98
List<TSQLStatement> statements = TSQLStatementReader.ParseStatements(
@"SELECT CAST(123.45 AS INT), CAST(456.321 AS VARCHAR(10)), Column_1 FROM MyTable",
includeWhitespace: false);

// should system properties be split out from system functions?
// what should each be named?
Assert.AreEqual(1, statements.Count);
TSQLSelectStatement select = statements.Single().AsSelect;
Assert.AreEqual(21, select.Tokens.Count);
Assert.AreEqual(3, select.Select.Columns.Count);
TSQLFunctionExpression function = select.Select.Columns[0].Expression.AsFunction;
Assert.AreEqual(6, function.Tokens.Count);
TSQLValueAsTypeExpression argument = function.Arguments[0].AsValueAsType;
Assert.AreEqual(3, argument.Tokens.Count);
Assert.AreEqual(123.45, argument.Expression.AsConstant.Literal.AsNumericLiteral.Value);
Assert.AreEqual("INT", argument.DataType);
function = select.Select.Columns[1].Expression.AsFunction;
Assert.AreEqual(9, function.Tokens.Count);
argument = function.Arguments[0].AsValueAsType;
Assert.AreEqual(6, argument.Tokens.Count);
Assert.AreEqual(456.321, argument.Expression.AsConstant.Literal.AsNumericLiteral.Value);
Assert.AreEqual("VARCHAR(10)", argument.DataType);
}

[Test]
public void SelectStatement_CAST_argument_parsing_with_whitespace()
{
// regression test for https://github.com/bruce-dunwiddie/tsql-parser/issues/98
List<TSQLStatement> statements = TSQLStatementReader.ParseStatements(
@"SELECT CAST(123.45 AS INT), CAST(456.321 AS VARCHAR(10) ), Column_1 FROM MyTable",
includeWhitespace: true);

Assert.AreEqual(1, statements.Count);
TSQLSelectStatement select = statements.Single().AsSelect;
Assert.AreEqual(2, select.Tokens.Count);
Assert.AreEqual("system_user", select.Select.Columns[0].Expression.AsColumn.Column.Name);
Assert.AreEqual(31, select.Tokens.Count);
Assert.AreEqual(3, select.Select.Columns.Count);
TSQLFunctionExpression function = select.Select.Columns[0].Expression.AsFunction;
Assert.AreEqual(8, function.Tokens.Count);
TSQLValueAsTypeExpression argument = function.Arguments[0].AsValueAsType;
Assert.AreEqual(5, argument.Tokens.Count);
Assert.AreEqual(123.45, argument.Expression.AsConstant.Literal.AsNumericLiteral.Value);
Assert.AreEqual("INT", argument.DataType);
function = select.Select.Columns[1].Expression.AsFunction;
Assert.AreEqual(12, function.Tokens.Count);
argument = function.Arguments[0].AsValueAsType;
Assert.AreEqual(9, argument.Tokens.Count);
Assert.AreEqual(456.321, argument.Expression.AsConstant.Literal.AsNumericLiteral.Value);
Assert.AreEqual("VARCHAR(10)", argument.DataType);
}
}
}
10 changes: 5 additions & 5 deletions TSQL_Parser/Tests/Tokens/IncompleteTokenTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void IncompleteToken_StringLiteral()
TokenComparisons.CompareTokenLists(
new List<TSQLToken>()
{
new TSQLIncompleteStringToken(0, "'")
new TSQLIncompleteString(0, "'")
},
tokens);
Assert.IsFalse(tokens[0].IsComplete);
Expand All @@ -34,7 +34,7 @@ public void IncompleteToken_Identifier()
TokenComparisons.CompareTokenLists(
new List<TSQLToken>()
{
new TSQLIncompleteIdentifierToken(0, "[dbo")
new TSQLIncompleteIdentifier(0, "[dbo")
},
tokens);
Assert.IsFalse(tokens[0].IsComplete);
Expand All @@ -47,7 +47,7 @@ public void IncompleteToken_Comment()
TokenComparisons.CompareTokenLists(
new List<TSQLToken>()
{
new TSQLIncompleteCommentToken(0, "/* something")
new TSQLIncompleteComment(0, "/* something")
},
tokens);
Assert.IsFalse(tokens[0].IsComplete);
Expand All @@ -63,7 +63,7 @@ public void IncompleteToken_DoubleQuoteIdentifier()
TokenComparisons.CompareTokenLists(
new List<TSQLToken>()
{
new TSQLIncompleteIdentifierToken(0, "\"dbo")
new TSQLIncompleteIdentifier(0, "\"dbo")
},
tokens);
Assert.IsFalse(tokens[0].IsComplete);
Expand All @@ -79,7 +79,7 @@ public void IncompleteToken_DoubleQuoteString()
TokenComparisons.CompareTokenLists(
new List<TSQLToken>()
{
new TSQLIncompleteStringToken(0, "\"something")
new TSQLIncompleteString(0, "\"something")
},
tokens);
Assert.IsFalse(tokens[0].IsComplete);
Expand Down

0 comments on commit 724c330

Please sign in to comment.