private static string ExtractConstant(SqlParseTreeNode node) { string pattern = @"XVAR\((?<dataType>.+?),(?<ownership>.+?),\s*Value=(?<value>.+?)\)"; Match match = Regex.Match(node.Arguments, pattern); if (match.Success) { string dataType = match.Groups["dataType"].Value; string ownership = match.Groups["ownership"].Value; string value = match.Groups["value"].Value; if (value.StartsWith("Len,Data = ")) { value += ")"; pattern = @"\((?<length>.+?),(?<value>.+?)\)"; match = Regex.Match(value, pattern); if (match.Success) { string length = match.Groups["length"].Value; value = match.Groups["value"].Value; } } return($"({dataType}) {value.Trim()}"); } return("<unknown>"); }
private static string ExtractTableNameAndAlias(SqlParseTreeNode node) { // Quick and dirty; probably has some cases where this isn't going to work if (string.IsNullOrEmpty(node.Arguments)) { return(string.Empty); } string tableLabel = "TBL: "; string aliasLabel = "alias TBL: "; int tableLabelIndex = node.Arguments.IndexOf(tableLabel, StringComparison.InvariantCultureIgnoreCase); if (tableLabelIndex < 0) { return(string.Empty); } bool inEscape = false; bool hasAlias = false; int aliasStartIndex = 0; StringBuilder sb = new StringBuilder(); for (int index = tableLabelIndex + tableLabel.Length; index < node.Arguments.Length; index++) { char c = node.Arguments[index]; if (c == '[') { inEscape = true; } if (c == ']' && inEscape == true) { inEscape = false; } if (c == ' ' && inEscape == false) { break; } if (c == '(' && inEscape == false) { if (node.Arguments.Substring(index + 1).StartsWith(aliasLabel, StringComparison.InvariantCultureIgnoreCase)) { hasAlias = true; aliasStartIndex = index + aliasLabel.Length + 1; } break; } sb.Append(c); } if (hasAlias) { int closeParenIndex = node.Arguments.IndexOf(")", aliasStartIndex, StringComparison.InvariantCultureIgnoreCase); string aliasName = node.Arguments.Substring(aliasStartIndex, closeParenIndex - aliasStartIndex); sb.Append($" ({aliasName})"); } return(sb.ToString()); }
private static SqlParseTreeNode ConvertNodeListToTree(List <SqlParseTreeNode> nodeList) { if (nodeList == null || nodeList.Count == 0) { return(new SqlParseTreeNode()); } SqlParseTreeNode rootNode = nodeList[0]; SqlParseTreeNode previousNode = rootNode; for (int nodeIndex = 1; nodeIndex < nodeList.Count; nodeIndex++) { SqlParseTreeNode node = nodeList[nodeIndex]; if (node.Level > previousNode.Level) { node.Parent = previousNode; } else if (node.Level == previousNode.Level) { // If the previous node is currently considered to be the "root", need to split // the root so that we don't wind up with muliple roots. if (previousNode == rootNode) { rootNode = new SqlParseTreeNode(); rootNode.OperationName = string.Empty; previousNode.Parent = rootNode; } node.Parent = previousNode.Parent; } else { SqlParseTreeNode siblingSearchNode = previousNode.Parent; while (siblingSearchNode != null && siblingSearchNode.Level > node.Level) { siblingSearchNode = siblingSearchNode.Parent; } if (siblingSearchNode != null) { node.Parent = siblingSearchNode.Parent; } } if (node.Parent != null) { node.Parent.Children.Add(node); } previousNode = node; } return(rootNode); }
private static void MeasureNode(SqlParseTreeNode node, int depth, Dictionary <int, int> levelCounts) { if (levelCounts.ContainsKey(depth) == false) { levelCounts.Add(depth, 0); } levelCounts[depth]++; foreach (SqlParseTreeNode child in node.Children) { MeasureNode(child, depth + 1, levelCounts); } }
private static string ExtractColumnName(SqlParseTreeNode node) { string pattern = @"Q?COL:\s+(?<colName>.+)"; Match match = Regex.Match(node.Arguments, pattern); if (match.Success) { string columnName = match.Groups["colName"].Value; return(columnName.Trim()); } return("<unknown>"); }
public static SqlParseTree Clone(SqlParseTree original) { if (original == null) { return(null); } SqlParseTree tree = new SqlParseTree(); tree.TreeDescription = original.TreeDescription; tree.RootNode = SqlParseTreeNode.Clone(original.RootNode); tree.OuterTreeText = original.OuterTreeText; tree.InnerTreeText = original.InnerTreeText; tree.BeginOffset = original.BeginOffset; tree.EndOffset = original.EndOffset; return(tree); }
public static SqlParseTreeNode Clone(SqlParseTreeNode original, SqlParseTreeNode newParent = null) { if (original == null) { return(null); } SqlParseTreeNode node = new SqlParseTreeNode(); node.SequenceNumber = original.SequenceNumber; node.Level = original.Level; node.OperationName = original.OperationName; node.Arguments = original.Arguments; node.Operation = original.Operation; node.Parent = newParent; node.Children = new List <SqlParseTreeNode>(); original.Children.ForEach(n => node.Children.Add(SqlParseTreeNode.Clone(n, node))); return(node); }
public static string GetLabel(SqlParseTreeNode node) { if (node.OperationName == "LogOp_Get") { string tableName = ExtractTableNameAndAlias(node); return($"Get {tableName}"); } if (node.OperationName == "ScaOp_Identifier") { string columnName = ExtractColumnName(node); return($"{columnName}"); } if (node.OperationName == "ScaOp_Const") { string constant = ExtractConstant(node); return($"{constant}"); } return(node.OperationName); }
private static SqlParseTreeNode ParseSingleNode(string parseLine) { SqlParseTreeNode node = new SqlParseTreeNode(); // Determine level by how many tabs prefix the text. int spaces = CountLeadingSpaces(parseLine); //node.Level = spaces / 4; node.Level = spaces; // Determine the operation name parseLine = parseLine.TrimStart(); parseLine = FixupLine(parseLine); int spaceIndex = parseLine.IndexOfAny(_operatorSeparatorChars); if (spaceIndex < 0) { node.OperationName = parseLine; parseLine = string.Empty; } else { node.OperationName = parseLine.Substring(0, spaceIndex); parseLine = parseLine.Substring(spaceIndex).TrimStart(); } OperationType operationType; if (Enum.TryParse(node.OperationName, out operationType)) { node.Operation = operationType; } // Arguments is the remainder node.Arguments = parseLine; return(node); }
public static ReadOnlyCollection <SqlParseTree> Parse(string treeText) { if (string.IsNullOrEmpty(treeText)) { return(new ReadOnlyCollection <SqlParseTree>(new List <SqlParseTree>())); } List <SqlParseTree> trees = new List <SqlParseTree>(); List <SqlParseTreeNode> nodes = new List <SqlParseTreeNode>(); SqlParseTree tree = null; StringBuilder sb = new StringBuilder(); using (StringReader reader = new StringReader(treeText)) { string line; int lineNumber = 0; SqlParseTreeNode previousNode = null; while ((line = reader.ReadLine()) != null) { if (line.StartsWith(_endMarker) && line.StartsWith(_ruleAppliedMarker) == false && tree != null) { // End of current tree reached. // TODO: determine offset at end tree.EndOffset = 0; tree.InnerTreeText = sb.ToString(); } else if (line.StartsWith(_beginMarker) || line.StartsWith(_ruleAppliedMarker)) { if (tree != null) { tree.RootNode = ConvertNodeListToTree(nodes); tree.InnerTreeText = sb.ToString(); trees.Add(tree); nodes = new List <SqlParseTreeNode>(); sb = new StringBuilder(); } tree = new SqlParseTree(); tree.OuterTreeText = treeText; tree.BeginOffset = 0; tree.TreeDescription = ExtractTreeDescription(line); } else if (line.StartsWith(" ") == false) { //throw new ApplicationException(string.Format("Unknown text {0} in parse tree text (no indentation?)", line)); } else { if ((line.Trim().Length > 0 && line.Trim().StartsWith("=") && previousNode != null) || (previousNode != null && previousNode.OperationName == "Exchange" && previousNode.Arguments == "Partition")) { // Continuation of previous line previousNode.Arguments += line; sb.AppendLine(line); } else { SqlParseTreeNode node = ParseSingleNode(line); node.SequenceNumber = lineNumber; nodes.Add(node); sb.AppendLine(line); previousNode = node; lineNumber++; } } } } if (tree != null) { tree.RootNode = ConvertNodeListToTree(nodes); tree.EndOffset = 0; tree.InnerTreeText = sb.ToString(); trees.Add(tree); } SetTreeOrder(trees); return(new ReadOnlyCollection <SqlParseTree>(trees)); }