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");
        }
示例#2
0
        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));
 }
示例#4
0
        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");
        }
示例#6
0
        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);
        }
示例#7
0
        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);
        }
示例#8
0
        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));
 }