public void ShouldResolveMaxFunction() { //Arrange string rawTsql = "MAX(CAST(timestamp as bigint))"; IExpressionResolver resolver = new TsqlFunctionResolver(); int fileIndex = 0; CompilerContext context = new CompilerContext("xUnit", "irrelevant", "irrelevant", true); ReadOnlySpan <TSQLToken> tokens = TSQLTokenizer.ParseTokens(rawTsql).ToArray(); //Act Expression expression = resolver.Resolve(tokens, ref fileIndex, context); //Assert Assert.Equal(tokens.Length, fileIndex); }
public void ShouldResolveHashBytesFunction() { //Arrange string rawTsql = "hashbytes ('sha1337', isNull(cast(somecolumn_01 as varchar), '') " + "+ isNull(cast(cast(somecolumn_02 as date) as varchar), '')" + "+ isNull(cast(somecolumn_04 collate Latin1_General_CI_AS as NVARCHAR(64)), ''))"; IExpressionResolver resolver = new TsqlFunctionResolver(); int fileIndex = 0; CompilerContext context = new CompilerContext("xUnit", "irrelevant", "irrelevant", true); ReadOnlySpan <TSQLToken> tokens = TSQLTokenizer.ParseTokens(rawTsql).ToArray(); //Act Expression expression = resolver.Resolve(tokens, ref fileIndex, context); //Assert Assert.Equal(tokens.Length, fileIndex); }
/// <summary> /// Resolves a database object and adds it to the current context as well /// as to the landscape /// </summary> /// <param name="asTargetTable">If the database object is expected to be a target table standart database and server are /// not added. We also may expect an opening bracket directly after the identifier which is the then not count as a function start</param> /// <returns>The database object</returns> internal static DatabaseObject ResolveDatabaseObject(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context, bool asTargetTable = false) { DatabaseObject dbo; if (tokens[fileIndex].Text.Equals("(")) { fileIndex++; //skip '(' dbo = ResolveDatabaseObject(tokens, ref fileIndex, context, asTargetTable); fileIndex++; //skip ')' } else if (tokens[fileIndex].Text.ToLower().Equals("select")) { var resolver = new SelectStatementResolver(); var statement = resolver.Resolve(tokens, ref fileIndex, context); dbo = new DatabaseObject(DatabaseObjectType.SELECTION); dbo.Expressions.AddRange(statement.ChildExpressions); } else if (tokens[fileIndex].Type.Equals(TSQLTokenType.Identifier)) { int positionBeforeNotationResolution = fileIndex; string notation = ResolveDatabaseObjectIdentifier(tokens, ref fileIndex); if (tokens.Length > fileIndex && tokens[fileIndex].Text.Equals("(") && !asTargetTable) { //In this section we asssume that the database object is returned by a function fileIndex = positionBeforeNotationResolution; var functionResolver = new TsqlFunctionResolver(); var function = functionResolver.Resolve(tokens, ref fileIndex, context); dbo = new DatabaseObject(DatabaseObjectType.SELECTION); dbo.Expressions.Add(function); } else { dbo = new DatabaseObject(notation, context, DatabaseObjectType.REAL, !asTargetTable); } } else if (tokens[fileIndex].Type.Equals(TSQLTokenType.Variable)) { dbo = new DatabaseObject(DatabaseObjectType.VARIABLE) { Name = tokens[fileIndex].Text, Database = InternalConstants.UNRELATED_DATABASE_NAME, Schema = InternalConstants.UNRELATED_SCHEMA_NAME, Server = InternalConstants.UNRELATED_SERVER_NAME }; fileIndex++; } else if (tokens[fileIndex].Type.Equals(TSQLTokenType.StringLiteral) || tokens[fileIndex].Type.Equals(TSQLTokenType.NumericLiteral) || tokens[fileIndex].Type.Equals(TSQLTokenType.BinaryLiteral)) { //The dbo is a set of constants e.g. ('Design Engineer', 'Tool Designer', 'Marketing Assistant') var dataset = ResolvesDataSet(tokens, ref fileIndex, context); dbo = new DatabaseObject(DatabaseObjectType.SET); dbo.Expressions.Add(dataset); } else if (tokens[fileIndex].Text.Equals("openquery", StringComparison.InvariantCultureIgnoreCase)) { dbo = new OpenQueryStatementResolver().Resolve(tokens, ref fileIndex, context); } else { throw new InvalidSqlException("Invalid database object"); } SkipTableHints(tokens, ref fileIndex); string alias = ResolveAlias(tokens, ref fileIndex, context); if (!string.IsNullOrEmpty(alias)) { dbo.Alias = alias; } SkipTableHints(tokens, ref fileIndex); //Table hints can appear before OR after an alias return(dbo); }