public void BuildSymbolTable_TableNameAlreadyDefined() { var ast = new SqlSelectNode { Columns = new SqlListNode <ISqlNode> { new SqlQualifiedIdentifierNode { Qualifier = new SqlIdentifierNode("MyTable"), Identifier = new SqlIdentifierNode("ColumnA") } }, FromClause = new SqlJoinNode { Left = new SqlIdentifierNode { Name = "MyTable" }, Operator = new SqlOperatorNode("NATURAL JOIN"), Right = new SqlIdentifierNode { Name = "MyTable" } } }; Action act = () => ast.BuildSymbolTables(); act.Should().Throw <SymbolAlreadyDefinedException>().And.Symbol.Should().Be("MyTable"); }
private ISqlNode ParseQuerySpecificiation(ITokenizer t) { // "SELECT" ... var selectToken = t.Expect(SqlTokenType.Keyword, "SELECT"); var selectNode = new SqlSelectNode { Location = selectToken.Location }; var modifier = t.Peek(); if (modifier.IsKeyword("ALL") || modifier.IsKeyword("DISTINCT")) { t.GetNext(); selectNode.Modifier = modifier.Value; } selectNode.Columns = ParseList(t, ParseSelectColumn); selectNode.FromClause = ParseSelectFromClause(t); selectNode.WhereClause = ParseWhereClause(t); selectNode.GroupByClause = ParseSelectGroupByClause(t); selectNode.HavingClause = ParseSelectHavingClause(t); selectNode.OrderByClause = ParseSelectOrderByClause(t); selectNode.TopLimitClause = ParseSelectLimitClause(t); selectNode.OffsetClause = ParseSelectOffsetClause(t); selectNode.FetchClause = ParseSelectFetchClause(t); return(selectNode); }
public override ISqlNode VisitSelect(SqlSelectNode n) { _result.AssertIsNotNullOrEmpty(n, nameof(n.Columns), n.Columns); // TODO: If the FROM clause contains a SELECT or values subquery, it MUST be in a parenthesis node // TODO: If the FROM clause contains a VALUES expression, it MUST be aliased and have ColumnNames return(base.VisitSelect(n)); }
public virtual ISqlNode VisitSelect(SqlSelectNode n) { var top = Visit(n.TopLimitClause) as SqlTopLimitNode; var columns = Visit(n.Columns) as SqlListNode <ISqlNode>; var from = Visit(n.FromClause); var where = Visit(n.WhereClause); var orderBy = Visit(n.OrderByClause) as SqlOrderByNode; var groupBy = Visit(n.GroupByClause); var having = Visit(n.HavingClause); var offset = Visit(n.OffsetClause); var fetch = Visit(n.FetchClause); return(n.Update(n.Modifier, top, columns, from, where, orderBy, groupBy, having, offset, fetch)); }
public void BuildSymbolTable_TableNameNotDefined() { var ast = new SqlSelectNode { Columns = new SqlListNode <ISqlNode> { new SqlQualifiedIdentifierNode { Qualifier = new SqlIdentifierNode("MyTable2"), Identifier = new SqlIdentifierNode("ColumnA") } }, FromClause = new SqlIdentifierNode { Name = "MyTable1" } }; Action act = () => ast.BuildSymbolTables(); act.Should().Throw <SymbolNotDefinedException>().And.Symbol.Should().Be("MyTable2"); }
public void BuildSymbolTable_TableName() { var ast = new SqlSelectNode { Columns = new SqlListNode <ISqlNode> { new SqlQualifiedIdentifierNode { Qualifier = new SqlIdentifierNode("MyTable"), Identifier = new SqlIdentifierNode("ColumnA") } }, FromClause = new SqlIdentifierNode { Name = "MyTable" } }; ast.BuildSymbolTables(); ast.Symbols.GetInfoOrThrow("MyTable", null).OriginKind.Should().Be(SymbolOriginKind.Environmental); ast.Symbols.GetInfoOrThrow("ColumnA", null).OriginKind.Should().Be(SymbolOriginKind.Environmental); }
public ISqlNode VisitSelect(SqlSelectNode n) { Append("SELECT "); if (n.Modifier != null) { Append(n.Modifier); Append(" "); } IncreaseIndent(); if (n.TopLimitClause != null) { AppendLineAndIndent(); Visit(n.TopLimitClause); } AppendLineAndIndent(); VisitList(n.Columns, () => AppendLineAndIndent(",")); if (n.FromClause != null) { AppendLineAndIndent(); AppendLine("FROM "); IncreaseIndent(); WriteIndent(); Visit(n.FromClause); DecreaseIndent(); } if (n.WhereClause != null) { AppendLineAndIndent(); AppendLine("WHERE"); IncreaseIndent(); WriteIndent(); Visit(n.WhereClause); DecreaseIndent(); } if (n.GroupByClause != null) { AppendLineAndIndent(); Append("GROUP BY"); IncreaseIndent(); AppendLineAndIndent(); Visit(n.GroupByClause); DecreaseIndent(); } if (n.HavingClause != null) { AppendLineAndIndent(); AppendLine("HAVING"); IncreaseIndent(); WriteIndent(); Visit(n.HavingClause); DecreaseIndent(); } if (n.OrderByClause != null) { AppendLineAndIndent(); Visit(n.OrderByClause); } if (n.OffsetClause != null) { AppendLineAndIndent(); Append("OFFSET ", n.OffsetClause, " ROWS"); } if (n.FetchClause != null) { AppendLineAndIndent(); Append("FETCH NEXT ", n.FetchClause, " ROWS ONLY"); } DecreaseIndent(); return(n); }
public override ISqlNode VisitSelect(SqlSelectNode n) { var symbols = PushSymbolTable(); // Visit the FROM clause to get all the source table expressions AddTableIds(n.FromClause); Visit(n.FromClause); // Visit the columns to get all column names and aliases foreach (var column in n.Columns) { if (column is SqlAliasNode alias) { Current.AddSymbol(alias.Alias.Name, new SymbolInfo { OriginalName = alias.Alias.Name, OriginKind = SymbolOriginKind.Alias, ObjectKind = ObjectKind.Scalar, DefinedAt = alias.Location }); } // Identifiers are presumed to be column names from tables in the FROM list if (column is SqlIdentifierNode id) { // TODO: Should check the symbol table first to see if we have this // identifier defined. Current.AddSymbol(id.ToString(), new SymbolInfo { OriginalName = id.ToString(), OriginKind = SymbolOriginKind.UserDeclared, ObjectKind = ObjectKind.Scalar, DefinedAt = id.Location }); } // Qualified IDs are presumed <tableOrAlias>.<column> if (column is SqlQualifiedIdentifierNode qid) { // Make sure the table name is already defined in the FROM clause Current.GetInfoOrThrow(qid.Qualifier.Name, n.Location); // We want <table>.<column>, not <table>.* // TODO: Would like to be able to look it up by short-name and fully-qualified name if (qid.Identifier is SqlIdentifierNode nested) { Current.AddSymbol(nested.Name, new SymbolInfo { OriginalName = qid.ToString(), OriginKind = SymbolOriginKind.Environmental, ObjectKind = ObjectKind.Scalar, DefinedAt = qid.Location }); } } // Variable should already be defined // TODO: We'll need to pre-populate the symbol table with out-of-scope parameter // declarations so we can make sure those are handled correctly. if (column is SqlVariableNode v) { Current.GetInfoOrThrow(v.Name, n.Location); } } Visit(n.WhereClause); Visit(n.GroupByClause); Visit(n.HavingClause); Visit(n.OrderByClause); n.Symbols = symbols; PopSymbolTable(); return(n); }
public override ISqlNode VisitSelect(SqlSelectNode n) { // TODO: if SELECT WHERE can reduce to TRUE, the where clause can be omitted // TODO: If SELECT WHERE can reduce to FALSE, the entire statement can be replaced with an empty result set return(base.VisitSelect(n)); }