private void ResolveGroupByClause(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            if (fileIndex >= tokens.Length || !tokens[fileIndex].Text.ToLower().Equals("group"))
            {
                return;
            }
            else
            {
                fileIndex += 2; //skip 'group by'
            }

            do
            {
                StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

                if (fileIndex >= tokens.Length)
                {
                    break;
                }

                if (tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++;
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);
        }
示例#2
0
        /// <summary>
        /// Resolves a Set clause
        /// </summary>
        private void ResolveSetClause(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            do
            {
                var target = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context); //resolve target column

                AddTargetObject(target);

                fileIndex++;                                                                           //skip '='

                var source = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context); //resolve source column
                target.ChildExpressions.Add(source);

                manipulation.Expressions.Add(target);

                if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ','
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);
        }
示例#3
0
        private void DetermineTargetColumns(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            if (tokens[fileIndex].Text.Equals("("))
            {
                fileIndex++; // skip '('
            }
            else
            {
                return;
            }

            do
            {
                var target = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                AddTargetObject(target);
                targets.Add(target);

                if (tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ','
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);

            fileIndex++; //skip ')'

            return;
        }
        public Expression Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            List <Expression> expressions = new List <Expression>();

            string functionName = tokens[fileIndex].Text.ToUpper();

            fileIndex++; //skiptype

            if (tokens[fileIndex].Text.Equals("("))
            {
                fileIndex++; //skip "("

                if (tokens[fileIndex].Text.Equals("max") || tokens[fileIndex].Text.Equals("min"))
                {
                    fileIndex++;
                }
                else
                {
                    do
                    {
                        var innerExpression = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

                        if (innerExpression.Type.Equals(ExpressionType.COLUMN))
                        {
                            expressions.Add(innerExpression);
                        }

                        if (tokens[fileIndex].Text.Equals(","))
                        {
                            fileIndex++; //skip ','
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }while (true);
                }

                fileIndex++; //skip ")"
            }

            if (expressions.Count == 1)
            {
                return(expressions[0]);
            }
            else
            {
                return(new Expression(ExpressionType.SCALAR_FUNCTION)
                {
                    Name = functionName,
                    ChildExpressions = expressions
                });
            }
        }
示例#5
0
        public void ShouldResolveAllColumnsSynonymous()
        {
            //Arrange
            string                   expression = "*";
            CompilerContext          context    = new CompilerContext("xUnit", "irrelevant", "irrelevant", true);
            int                      fileIndex  = 0;
            ReadOnlySpan <TSQLToken> tokens     = TSQLTokenizer.ParseTokens(expression).ToArray();

            //Act
            var result = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

            //Assert
            Assert.Equal("*", result.Name);
            Assert.Equal(ExpressionType.COLUMN, result.Type);
        }
示例#6
0
        private void SkipTopExpression(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            if (!tokens[fileIndex].Text.ToLower().Equals("top"))
            {
                return;
            }

            fileIndex++; //skip top

            StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

            if (tokens[fileIndex].Text.ToLower().Equals("percent"))
            {
                fileIndex++;
            }
        }
示例#7
0
        /// <summary>
        /// We are not interested in the actual statement, so just skip it
        /// </summary>
        public void Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            fileIndex++; //skip 'create'

            switch (tokens[fileIndex].Text.ToLower())
            {
            case "table":
            {
                fileIndex += 2;
                MoveToFinalBracket(tokens, ref fileIndex);
                break;
            }

            case "unique":
            case "clustered":
            case "nonclustered":
            {
                while (!tokens[fileIndex].Text.Equals("("))
                {
                    fileIndex++;
                }

                MoveToFinalBracket(tokens, ref fileIndex);         //skip column name

                if (tokens[fileIndex].Text.ToLower().Equals("include"))
                {
                    fileIndex++;
                    MoveToFinalBracket(tokens, ref fileIndex);
                }
                if (tokens[fileIndex].Text.ToLower().Equals("with"))
                {
                    fileIndex++;
                    MoveToFinalBracket(tokens, ref fileIndex);
                }
                if (tokens[fileIndex].Text.ToLower().Equals("on"))
                {
                    fileIndex++;
                    StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                }

                break;
            }
            }
        }
        public Expression Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            List <Expression> expressions = new List <Expression>();

            fileIndex += 2; //Skip 'cast ('

            Expression innerExpression = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

            if (innerExpression.Type.Equals(ExpressionType.COLUMN))
            {
                expressions.Add(innerExpression);
            }
            else if (innerExpression.Type.Equals(ExpressionType.COMPLEX) || innerExpression.Type.Equals(ExpressionType.SCALAR_FUNCTION))
            {
                expressions.AddRange(innerExpression.ChildExpressions);
            }

            fileIndex++;  //skip 'as'

            TypeCasterResolver caster = new TypeCasterResolver();

            caster.Resolve(tokens, ref fileIndex, context);

            if (!tokens[fileIndex].Text.Equals(")"))
            {
                throw new InvalidSqlException("Cast statement does not end with a closing bracket");
            }

            fileIndex++; //skip ')'

            if (expressions.Count != 1)
            {
                return(new Expression(ExpressionType.SCALAR_FUNCTION)
                {
                    Name = "CAST",
                    ChildExpressions = expressions
                });
            }
            else
            {
                return(expressions[0]);
            }
        }
示例#9
0
        private void DetermineSourceObjects(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            do
            {
                var source = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                sources.Add(source);

                if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ','
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);

            fileIndex++; //skip ')'
        }
示例#10
0
        /// <summary>
        /// Gets called when the rows didnt match
        /// </summary>
        private void ResolveMergeNotMatched(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            if (!tokens[fileIndex].Text.Equals("insert", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new InvalidSqlException("A 'WHEN NOT MATCHED'-clause did not contain an INSERT statement");
            }

            List <Expression> targets = new List <Expression>();

            List <Expression> sources = new List <Expression>();

            fileIndex++; //skip 'insert'

            if (tokens[fileIndex].Text.Equals("("))
            {
                fileIndex++; //skip '('

                do
                {
                    var target = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                    AddTargetObject(target);
                    targets.Add(target);

                    if (tokens[fileIndex].Text.Equals(","))
                    {
                        fileIndex++; //skip ','
                        continue;
                    }
                    else
                    {
                        break;
                    }
                } while (true);

                fileIndex++; //skip ')'
            }

            if (tokens[fileIndex].Text.Equals("values", StringComparison.InvariantCultureIgnoreCase))
            {
                fileIndex += 2; //skip 'values ('

                do
                {
                    var source = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                    sources.Add(source);

                    if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals(","))
                    {
                        fileIndex++; //skip ','
                        continue;
                    }
                    else
                    {
                        break;
                    }
                } while (true);

                fileIndex++; //skip ')'

                if (targets.Count != sources.Count)
                {
                    throw new InvalidSqlException("Unable to resolve MERGE statement.");
                }

                for (int counter = 0; counter < targets.Count; counter++)
                {
                    targets[counter].ChildExpressions.Add(sources[counter]);
                    manipulation.Expressions.Add(targets[counter]);
                }
            }
            else if (tokens[fileIndex].Text.Equals("default", StringComparison.InvariantCultureIgnoreCase))
            {
                fileIndex += 2; //skip 'default values'
            }
            else
            {
                throw new InvalidSqlException("Unable to compile ");
            }
        }
        internal void Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            fileIndex++; //skip 'with'

            do
            {
                var alias = tokens[fileIndex].Text.ToLower();

                if (string.IsNullOrEmpty(alias))
                {
                    throw new InvalidSqlException("Common table expression must have an alias");
                }

                fileIndex++; //skip alias

                List <Expression> columns = new List <Expression>();

                if (!tokens[fileIndex].Text.Equals("as", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (tokens[fileIndex].Text.Equals("("))
                    {
                        fileIndex++; //skip '('
                    }
                    do
                    {
                        var column = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

                        if (!column.Type.Equals(ExpressionType.COLUMN))
                        {
                            throw new InvalidSqlException("Common Table Expressions only may contain conrete columns");
                        }

                        columns.Add(column);

                        if (tokens[fileIndex].Text.Equals(","))
                        {
                            fileIndex++; //skip ','
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }while (true);

                    if (tokens[fileIndex].Text.Equals(")"))
                    {
                        fileIndex++; //skip ')'
                    }
                }

                fileIndex++; //skip 'as'

                var cte = StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context);
                cte.Alias       = alias;
                cte.Type        = DatabaseObjectType.CTE;
                cte.Expressions = columns;

                context.CurrentDatabaseObjectContext.Push(cte);

                if (tokens.Length > fileIndex && tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ','
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);
        }
示例#12
0
        /// <summary>
        /// The method of death. Dont change anything. Trust me, just dont.
        /// </summary>
        private static void ResolveConcatenatedConditions(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context, ref bool expectingSecondPart)
        {
            bool expectDatabaseObject            = false;
            bool isSecondPartofBetweenExpression = false;

            do
            {
                if (tokens.Length <= fileIndex)
                {
                    break;
                }

                if (tokens[fileIndex].Text.ToLower().Equals("not") || Operators.IsUnaryOperator(tokens[fileIndex].Text.ToLower()))
                {
                    fileIndex++; //skip operator
                }
                if (IsLogicalExpressionOperator(tokens[fileIndex].Text.ToLower()))
                {
                    fileIndex++;
                }

                if (tokens[fileIndex].Text.Equals("("))
                {
                    fileIndex++; //skip '('
                    ResolveConcatenatedConditions(tokens, ref fileIndex, context, ref expectingSecondPart);
                    fileIndex++; //skip ')'
                }
                else
                {
                    do
                    {
                        if (fileIndex < tokens.Length && tokens[fileIndex].Text.ToLower().Equals("null"))
                        {
                            fileIndex++; //skip null
                        }
                        else if (fileIndex < tokens.Length && (tokens[fileIndex].Text.ToLower().Equals("contains") || tokens[fileIndex].Text.ToLower().Equals("exists")))
                        {
                            var resolver = new TsqlFunctionResolver();
                            resolver.Resolve(tokens, ref fileIndex, context);
                            break;
                        }
                        else if (expectDatabaseObject)
                        {
                            StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context);
                        }
                        else
                        {
                            StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                            if (isSecondPartofBetweenExpression)
                            {
                                if (!tokens[fileIndex].Text.ToLower().Equals("and"))
                                {
                                    throw new InvalidSqlException("BETWEEN keyword was not followed by an AND");
                                }

                                fileIndex++; //skip 'AND'
                                StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                                isSecondPartofBetweenExpression = false;
                            }

                            if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals("escape", StringComparison.InvariantCultureIgnoreCase))
                            {
                                fileIndex += 2; // skip 'escape [pattern]'
                            }
                        }

                        if (expectingSecondPart)
                        {
                            expectingSecondPart = false;
                        }

                        if (fileIndex >= tokens.Length)
                        {
                            break;
                        }

                        if (tokens[fileIndex].Text.ToLower().Equals("not") || tokens[fileIndex].Text.ToLower().Equals("~"))
                        {
                            fileIndex++;
                        }

                        string possibleLogicalExpressionOperator = tokens[fileIndex].Text.ToLower();

                        if (possibleLogicalExpressionOperator.Equals("is"))
                        {
                            if (expectingSecondPart)
                            {
                                throw new InvalidSqlException("Expression contains multiple logical operators");
                            }

                            expectingSecondPart = true;
                            fileIndex++; // skip 'is'

                            if (tokens[fileIndex].Text.ToLower().Equals("not"))
                            {
                                fileIndex++;
                            }

                            continue;
                        }

                        if (possibleLogicalExpressionOperator.Equals("between"))
                        {
                            if (expectingSecondPart)
                            {
                                throw new InvalidSqlException("Expression contains multiple logical operators");
                            }

                            expectingSecondPart = true;
                            fileIndex++; // skip 'between'
                            isSecondPartofBetweenExpression = true;
                            continue;
                        }

                        if (possibleLogicalExpressionOperator.Equals("in"))
                        {
                            if (expectingSecondPart)
                            {
                                throw new InvalidSqlException("Expression contains multiple logical operators");
                            }

                            expectingSecondPart  = true;
                            expectDatabaseObject = true;
                            fileIndex++; // skip 'in'
                            continue;
                        }
                        else
                        {
                            expectDatabaseObject = false;
                        }

                        if (IsLogicalExpressionOperator(tokens[fileIndex].Text))
                        {
                            if (expectingSecondPart)
                            {
                                throw new InvalidSqlException("Expression contains multiple logical operators");
                            }

                            expectingSecondPart = !expectingSecondPart;

                            fileIndex++;
                            continue;
                        }



                        if (tokens[fileIndex].Text.ToLower().Equals("and") && isSecondPartofBetweenExpression)
                        {
                            fileIndex++;
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    } while (true);
                }

                if (tokens.Length > fileIndex && !expectingSecondPart && IsLogicalExpressionOperator(tokens[fileIndex].Text.ToLower()))
                {
                    expectingSecondPart = true;
                    fileIndex++; // skip 'operator'
                    continue;
                }

                if (tokens.Length > fileIndex && (tokens[fileIndex].Text.ToLower().Equals("and") || tokens[fileIndex].Text.ToLower().Equals("or")))
                {
                    fileIndex++;
                    continue;
                }
                else
                {
                    break;
                }
            }while (true);
        }
        public Expression Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            List <Expression> expressions  = new List <Expression>();
            string            functionName = "";

            if (tokens[fileIndex + 1].Text.Equals("::")) //Special function types eg: "geography::STPointFromText(........)"
            {
                fileIndex += 4;
            }
            else
            {
                functionName = tokens[fileIndex].Text.ToUpper();
                fileIndex   += 2; //skip function-keyword + '('
            }

            if (tokens[fileIndex].Text.Equals(")")) //parameterless function can be ignored
            {
                fileIndex++;
                return(new Expression(ExpressionType.SCALAR_FUNCTION)
                {
                    Name = functionName
                });
            }

            do
            {
                var parameter = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

                if (parameter.Type.Equals(ExpressionType.COMPLEX) || parameter.Type.Equals(ExpressionType.SCALAR_FUNCTION))
                {
                    foreach (var subExp in parameter.ChildExpressions)
                    {
                        expressions.Add(subExp);
                    }
                }
                else if (parameter.Type.Equals(ExpressionType.COLUMN))
                {
                    expressions.Add(parameter);
                }

                if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ","
                    continue;
                }
                else
                {
                    break;
                }
            }while (true);

            fileIndex++; //skip ')'

            if (expressions.Count != 1)
            {
                return(new Expression(ExpressionType.SCALAR_FUNCTION)
                {
                    Name = functionName,
                    ChildExpressions = expressions
                });
            }
            else
            {
                return(expressions[0]);
            }
        }
        public Expression Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            List <Expression> expressions = new List <Expression>();

            // The CASE expression has two formats: 'simple' and 'searched'. For more information visit:
            // https://docs.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql?view=sql-server-2017
            bool isSimpleFormat = false;

            fileIndex++; //skip "case"

            if (!tokens[fileIndex].Text.ToLower().Equals("when"))
            {
                isSimpleFormat = true;
                StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
            }

            do
            {
                fileIndex++; //skip 'when'

                if (isSimpleFormat)
                {
                    StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                }
                else
                {
                    SearchConditionResolver.Resolve(tokens, ref fileIndex, context);
                }

                fileIndex++; //skip 'then'

                Expression thenExpression = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                if (thenExpression.Type.Equals(ExpressionType.COLUMN))
                {
                    expressions.Add(thenExpression);
                }
                else if (thenExpression.Type.Equals(ExpressionType.COMPLEX) || thenExpression.Type.Equals(ExpressionType.SCALAR_FUNCTION))
                {
                    expressions.AddRange(thenExpression.ChildExpressions);
                }

                if (tokens.Length <= fileIndex)
                {
                    throw new InvalidSqlException("Trying to resolve case-statement without 'end'-keyword");
                }

                if (tokens[fileIndex].Text.ToLower().Equals("when"))
                {
                    continue;
                }

                if (tokens[fileIndex].Text.ToLower().Equals("else"))
                {
                    fileIndex++; //skip 'else'
                    Expression elseExpression = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                    if (elseExpression.Type.Equals(ExpressionType.COLUMN))
                    {
                        expressions.Add(elseExpression);
                    }
                    else if (elseExpression.Type.Equals(ExpressionType.COMPLEX) || elseExpression.Type.Equals(ExpressionType.SCALAR_FUNCTION))
                    {
                        expressions.AddRange(elseExpression.ChildExpressions);
                    }
                }

                if (tokens[fileIndex].Text.ToLower().Equals("end"))
                {
                    fileIndex++; //skip 'end'
                    break;
                }
            } while (true);

            if (expressions.Count == 1)
            {
                return(expressions[0]);
            }
            else
            {
                return(new Expression(ExpressionType.SCALAR_FUNCTION)
                {
                    Name = "CASE",
                    ChildExpressions = expressions
                });
            }
        }
        public DataManipulation Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            manipulation = new DataManipulation();

            fileIndex++; //skip 'update'

            var targetObject = StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context, true);

            fileIndex++; //skip 'set'

            do
            {
                //Resolves the target object. Note that this target can be an alias that is resolved later in the FROM statement
                var target = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

                AddTargetObject(target, targetObject);

                fileIndex++;                                                                           //skip '='

                var source = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context); //resolve source column
                target.ChildExpressions.Add(source);

                manipulation.Expressions.Add(target);

                if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ','
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);

            var objects = StatementResolveHelper.ResolveFromStatement(tokens, ref fileIndex, context);

            AddObjectsToContext(objects, context);

            if (objects.Count > 1)
            {
                targetObject = AssignRealTarget(objects, targetObject);
                var targetSynonymous = new Expression(ExpressionType.COLUMN)
                {
                    Name = Beautifier.EnhanceNotation(targetObject, InternalConstants.WHOLE_OBJECT_SYNONYMOUS),
                    WholeObjectSynonymous = true
                };

                foreach (var dbo in objects)
                {
                    if (!dbo.Type.Equals(DatabaseObjectType.REAL) || dbo.Equals(targetObject))
                    {
                        continue;
                    }
                    var sourceSynonymous = new Expression(ExpressionType.COLUMN)
                    {
                        Name = Beautifier.EnhanceNotation(dbo, InternalConstants.WHOLE_OBJECT_SYNONYMOUS),
                        WholeObjectSynonymous = true
                    };
                    targetSynonymous.ChildExpressions.Add(sourceSynonymous);
                    manipulation.Expressions.Add(targetSynonymous);
                }
            }

            var beautified = new List <Expression>();

            foreach (var expr in manipulation.Expressions)
            {
                beautified.Add(Beautifier.BeautifyColumns(expr, context));
            }

            manipulation.Expressions = beautified;

            StatementResolveHelper.ResolveWhereStatement(tokens, ref fileIndex, context);

            PopObjectsFromContextStack(context);

            return(manipulation);
        }
        /// <summary>
        /// Returns the query containing all data columns. The column properties (schema, table) may not have been assigned
        /// correctly after this function since the from statement still needs to resolved
        /// </summary>
        private Expression DetermineSourceColumns(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context)
        {
            Expression query = new Expression(ExpressionType.SCALAR_FUNCTION)
            {
                Name = "SELECT"
            };

            if (tokens[fileIndex].Text.Equals("*"))
            {
                var column = new Expression(ExpressionType.COLUMN)
                {
                    Name = tokens[fileIndex].Text
                };

                query.ChildExpressions.Add(column);
                fileIndex++;

                return(query);
            }

            do
            {
                var innerExpression = StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);

                if (fileIndex < tokens.Length && tokens[fileIndex].Text.ToLower().Equals("="))
                {
                    //An expression followed by a "=" is equivalent to: CASE WHEN col1 = col2 THEN 1 ELSE 0 END
                    fileIndex++; //skip '='
                    StatementResolveHelper.ResolveExpression(tokens, ref fileIndex, context);
                }

                if (fileIndex >= tokens.Length)
                {
                    return(query);
                }

                if (tokens[fileIndex].Text.ToLower().Equals("as"))
                {
                    fileIndex++; //skip as
                    string possibleAlias = tokens[fileIndex].Text;
                    fileIndex++; //skip alias
                    var aliasExpression = new Expression(ExpressionType.ALIAS)
                    {
                        Name = possibleAlias
                    };
                    aliasExpression.ChildExpressions.Add(innerExpression);
                    query.ChildExpressions.Add(aliasExpression);
                }
                else if (tokens[fileIndex].Type.Equals(TSQLTokenType.Identifier))
                {
                    string possibleAlias = tokens[fileIndex].Text;
                    fileIndex++; //skip alias
                    var aliasExpression = new Expression(ExpressionType.ALIAS)
                    {
                        Name = possibleAlias
                    };
                    aliasExpression.ChildExpressions.Add(innerExpression);
                    query.ChildExpressions.Add(aliasExpression);
                }
                else
                {
                    query.ChildExpressions.Add(innerExpression);
                }

                if (tokens[fileIndex].Text.Equals(","))
                {
                    fileIndex++; //skip ','
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);

            return(query);
        }