Skip to content

Commit

Permalink
Fix punctuation parsing
Browse files Browse the repository at this point in the history
Now parser can correctly handle:

```sql
CREATE TABLE users
(
    id         INT AUTO_INCREMENT,
    name       VARCHAR(122) NOT NULL UNIQUE,
    profile_id INT,
    PRIMARY KEY (id),
    FOREIGN KEY (id)
);
```

FK definition is still incomplete,
cause reference statement is not defined.
  • Loading branch information
Bardin08 committed Apr 17, 2024
1 parent fb40d5e commit 3b23403
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 14 deletions.
17 changes: 10 additions & 7 deletions DbSeeder/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ private static void Main()
{
const string sqlScript =
"""
CREATE TABLE Users (
Id INT PRIMARY KEY,
Name VARCHAR(122) NOT NULL UNIQUE,
ProfileId UUID FOREIGN KEY
CREATE TABLE users
(
id INT AUTO_INCREMENT,
name VARCHAR(122) NOT NULL UNIQUE,
profile_id INT,
PRIMARY KEY (id)
);

CREATE TABLE Profiles (
Id UUID PRIMARY KEY,
Nickname VARCHAR(122) NOT NULL UNIQUE,
CREATE TABLE profiles
(
id INT AUTO_INCREMENT PRIMARY KEY,
nickname VARCHAR(122) NOT NULL UNIQUE
);
""";
var lexer = new SqlLexer(sqlScript);
Expand Down
2 changes: 1 addition & 1 deletion DbSeeder/SqlParser/ParserConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class ParserConstants

public static readonly HashSet<string> Constraints =
[
"PRIMARY KEY", "FOREIGN KEY", "NOT NULL", "UNIQUE"
"PRIMARY KEY", "FOREIGN KEY", "NOT NULL", "UNIQUE", "AUTO_INCREMENT"
];

public static readonly SearchValues<char> Punctuation = SearchValues.Create("(),.;");
Expand Down
53 changes: 47 additions & 6 deletions DbSeeder/SqlParser/SyntaxTree/AstBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,14 @@ private void HandleIdentifier(SqlToken token, ref SyntaxTreeNode localRoot)
AddNode(SyntaxTreeNodeType.TableRoot, token.Value, ref localRoot!);
break;
case SyntaxTreeNodeType.TableColumns:
AddNode(SyntaxTreeNodeType.Column, token.Value, ref localRoot!);
if (!IsConstraint(token))
{
AddNode(SyntaxTreeNodeType.Column, token.Value, ref localRoot!);
}
else
{
BuildConstraint(token, ref localRoot);
}
break;
case SyntaxTreeNodeType.Column:
AddNode(SyntaxTreeNodeType.ColumnDataType, token.Value, ref localRoot!);
Expand All @@ -100,6 +107,25 @@ private void HandleIdentifier(SqlToken token, ref SyntaxTreeNode localRoot)
}
}

private bool IsConstraint(SqlToken token)
{
var isConstraintKeyWord = token.Value.Equals("constraint", StringComparison.OrdinalIgnoreCase);
var isIdentifier = ParserConstants.Constraints
.Any(c => c.Contains(token.Value, StringComparison.OrdinalIgnoreCase));

return isConstraintKeyWord || isIdentifier;
}

private void BuildConstraint(SqlToken token, ref SyntaxTreeNode localRoot)
{
Console.WriteLine($"Detected Constraint: {token.Value}");

AddNode(SyntaxTreeNodeType.ColumnConstraint, token.Value, ref localRoot!);



}

private void HandleColumnConstraintIdentifier(SqlToken token, ref SyntaxTreeNode localRoot)
{
// Handle composite constraints (e.g., NOT NULL)
Expand All @@ -108,6 +134,18 @@ private void HandleColumnConstraintIdentifier(SqlToken token, ref SyntaxTreeNode
var updatedConstraintValue = localRoot.Value + " " + token.Value;
UpdateColumnConstraintNode(updatedConstraintValue, ref localRoot);
}
else if (localRoot.Parent?.Type is SyntaxTreeNodeType.TableColumns)
{
// PRIMARY KEY (id). If we're here, we are looking at the col name.
var colsContainerNode = localRoot.Parent;

colsContainerNode.Children.Remove(localRoot);
var constraintOwner = colsContainerNode.Children.First(x => x!.Value.Equals(token.Value))!;

var temp = new SyntaxTreeNode(localRoot.Type, localRoot.Value, constraintOwner);
localRoot = temp;
constraintOwner.Children.Add(temp);
}
else
{
AddColumnConstraintNode(token, ref localRoot);
Expand Down Expand Up @@ -156,6 +194,7 @@ private void HandlePunctuation(SqlToken token, SyntaxTreeNode root, ref SyntaxTr
break;
case SyntaxTreeNodeType.ColumnConstraint:
case SyntaxTreeNodeType.ColumnDataType:
case SyntaxTreeNodeType.TableColumns:
HandleColumnConstraintOrDataTypePunctuation(token, ref localRoot);
break;
case SyntaxTreeNodeType.DataTypeConstraint:
Expand All @@ -165,7 +204,6 @@ private void HandlePunctuation(SqlToken token, SyntaxTreeNode root, ref SyntaxTr
case SyntaxTreeNodeType.Root:
case SyntaxTreeNodeType.CreateStatement:
case SyntaxTreeNodeType.CreateTable:
case SyntaxTreeNodeType.TableColumns:
case SyntaxTreeNodeType.Column:
default:
throw new NotImplementedException($"Punctuation is not expected after '{localRoot.Type}'");
Expand All @@ -190,10 +228,13 @@ private void HandleColumnConstraintOrDataTypePunctuation(SqlToken token, ref Syn
}
else
{
// For other punctuation, validate and potentially move back to TableColumns
EnsureNodeType(
ref localRoot,
SyntaxTreeNodeType.TableColumns);
if (localRoot.Type != SyntaxTreeNodeType.TableColumns)
{
// For other punctuation, validate and potentially move back to TableColumns
EnsureNodeType(
ref localRoot,
SyntaxTreeNodeType.TableColumns);
}
}
}

Expand Down

0 comments on commit 3b23403

Please sign in to comment.