private void ResolveIntoClause(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context) { if (fileIndex < tokens.Length && tokens[fileIndex].Text.ToLower().Equals("into")) { fileIndex++; var target = StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context); statement.TargetObject = target; } }
/// <summary> /// ATM this resolver just skips the statement without adding anything to the context /// </summary> public void Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context) { fileIndex += 2; //skip "bulk insert" StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context); if (!tokens[fileIndex].Text.ToLower().Equals("from")) { throw new InvalidSqlException("Missing 'from'-keyword in bulk insert statement"); } fileIndex++; //skip "from" string filePath = tokens[fileIndex].Text; fileIndex++; //skip file if (tokens[fileIndex].Text.ToLower().Equals("with")) { fileIndex += 2; //skip "with (" int openBracketCounter = 1; while (openBracketCounter > 0) { if (tokens[fileIndex].Text.Equals(")")) { openBracketCounter--; } if (tokens[fileIndex].Text.Equals("(")) { openBracketCounter++; } fileIndex++; } } }
private DatabaseObject ResolveUsingStatement(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context) { fileIndex++; //skip 'using' return(StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context)); }
public DataManipulation Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context) { manipulation = new DataManipulation(); fileIndex++; //skip "merge" //skip top expression SkipTopExpression(tokens, ref fileIndex, context); if (tokens[fileIndex].Text.ToLower().Equals("into")) { fileIndex++; } targetObject = StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context); context.AddDatabaseObjectToCurrentContext(targetObject); if (!tokens[fileIndex].Text.ToLower().Equals("using")) { throw new InvalidSqlException("Trying to resolve a merge-statement without using keyword"); } var source = ResolveUsingStatement(tokens, ref fileIndex, context); context.AddDatabaseObjectToCurrentContext(source); if (!tokens[fileIndex].Text.Equals("on", StringComparison.InvariantCultureIgnoreCase)) { throw new InvalidSqlException("Expected 'ON' keyword when resolving a 'MERGE'-statement"); } fileIndex++; //skip 'on' SearchConditionResolver.Resolve(tokens, ref fileIndex, context); while (tokens[fileIndex].Text.Equals("when", StringComparison.InvariantCultureIgnoreCase)) { ResolveWhenExpression(tokens, ref fileIndex, context); } var beautified = new List <Expression>(); foreach (var exp in manipulation.Expressions) { beautified.Add(Beautifier.BeautifyColumns(exp, context)); } manipulation.Expressions = beautified; while (!tokens[fileIndex].Text.ToLower().Equals(";")) { fileIndex++; if (fileIndex == tokens.Length) { throw new InvalidSqlException("Trying to resolve a merge-statement without proper ';' determination"); } } fileIndex++; //skip ';' context.CurrentDatabaseObjectContext.Pop(); return(manipulation); }
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); }
/// <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 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); }
public DataManipulation Resolve(ReadOnlySpan <TSQLToken> tokens, ref int fileIndex, CompilerContext context) { manipulation = new DataManipulation(); fileIndex++; //skip 'insert' //TODO Resolve TOP Expression if (tokens[fileIndex].Text.ToLower().Equals("into")) { fileIndex++; //skip 'into' } targetObject = StatementResolveHelper.ResolveDatabaseObject(tokens, ref fileIndex, context, true); DetermineTargetColumns(tokens, ref fileIndex, context); //TODO Resolve Table Hint if (tokens[fileIndex].Text.Equals("values", StringComparison.InvariantCultureIgnoreCase)) { fileIndex += 2; //skip 'values (' DetermineSourceObjects(tokens, ref fileIndex, context); } else if (tokens[fileIndex].Text.Equals("select", StringComparison.InvariantCultureIgnoreCase)) { var selectStatement = new SelectStatementResolver().Resolve(tokens, ref fileIndex, context); sources = selectStatement.ChildExpressions; } if (targets.Count == 0) { for (int index = 0; index < sources.Count; index++) { Expression resolvedSource; if (sources[index].Type.Equals(ExpressionType.COMPLEX) || sources[index].Type.Equals(ExpressionType.CONSTANT)) { continue; } else if (sources[index].Type.Equals(ExpressionType.ALIAS)) { resolvedSource = sources[index].ChildExpressions[0]; } else { resolvedSource = sources[index]; } var singleManipulation = new Expression(ExpressionType.COLUMN) { Name = Beautifier.EnhanceNotation(targetObject, InternalConstants.UNRELATED_COLUMN_NAME) }; singleManipulation.ChildExpressions.Add(resolvedSource); manipulation.Expressions.Add(singleManipulation); } } else if (StatementResolveHelper.HaveEqualAmountOfRealExpression(sources, targets)) { for (int index = 0; index < targets.Count; index++) { if (!sources[index].Type.Equals(ExpressionType.COLUMN) && !sources[index].Type.Equals(ExpressionType.SCALAR_FUNCTION)) { continue; } var singleManipulation = new Expression(ExpressionType.COLUMN) { Name = targets[index].Name }; singleManipulation.ChildExpressions.Add(sources[index]); manipulation.Expressions.Add(singleManipulation); } } else { throw new InvalidSqlException("Amount of targets does not match the number of sources"); } if (fileIndex < tokens.Length && tokens[fileIndex].Text.Equals(";")) { fileIndex++; } var beautified = new List <Expression>(); foreach (var exp in manipulation.Expressions) { beautified.Add(Beautifier.BeautifyColumns(exp, context)); } manipulation.Expressions = beautified; return(manipulation); }