我有一个3000多个查询的文件。对于每个查询,我都需要找出它引用的表。因此,我编写了以下一小段代码:
public class TableNameCollector : TSqlFragmentVisitor
{
public readonly SortedSet<string> TableNames = new(StringComparer.OrdinalIgnoreCase);
public override void Visit(NamedTableReference node)
{
switch (node.SchemaObject.Identifiers.Count)
{
case 1:
if (node.SchemaObject.Identifiers[0].Value[0] != '#')
{
TableNames.Add(node.SchemaObject.Identifiers[0].Value);
}
break;
case 2:
if ("dbo".Equals(node.SchemaObject.Identifiers[0].Value, StringComparison.OrdinalIgnoreCase))
{
TableNames.Add(node.SchemaObject.Identifiers[1].Value);
}
else if (!"INFORMATION_SCHEMA".Equals(node.SchemaObject.Identifiers[0].Value, StringComparison.OrdinalIgnoreCase))
{
TableNames.Add(node.SchemaObject.Identifiers[0].Value + '.' + node.SchemaObject.Identifiers[1].Value);
}
break;
default:
throw new NotSupportedException();
}
}
}
class Program
{
private class QueryItem
{
public readonly string QueryName;
public readonly string Sql;
public QueryItem(string queryName, string sql)
{
QueryName = queryName;
Sql = sql;
}
}
private class QueryInfo
{
public readonly string QueryName;
public readonly ICollection<string> TableNames;
public QueryInfo(string queryName, ICollection<string> tableNames)
{
QueryName = queryName;
TableNames = tableNames;
}
}
static void Main()
{
var parser = new TSql150Parser(true, SqlEngineType.Standalone);
var res = YieldQueryItems(ThePathToTheFile).Select(item => ProduceQueryInfo(item, parser)).ToList();
...
}
private static IEnumerable<QueryItem> YieldQueryItems(string dataSourceDefinitionFile) => ... ;
private static QueryInfo ProduceQueryInfo(QueryItem item, TSql150Parser parser)
{
var tree = parser.Parse(new StringReader(item.Sql), out var errors);
var visitor = new TableNameCollector();
tree.Accept(visitor);
return new QueryInfo(item.QueryName, visitor.TableNames);
}
}
以下是项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SqlServer.DacFx" Version="150.5164.1" />
</ItemGroup>
</Project>
而且效果很好。在VS IDE之外运行它大约需要3秒钟。然而,从IDE运行它需要很长时间。事实上,我从来没有留下来看着它结束——总是在一分钟左右后停止。
我怀疑这是因为解析器生成了无数第一次机会异常。比如:
Exception thrown: 'antlr.MismatchedTokenException' in Microsoft.SqlServer.TransactSql.ScriptDom.dll
我使用VS2019。
可以在VS IDE中抑制FCEs的输出吗?
顺便说一句,我在调试时禁用了诊断跟踪,因此这不是根本原因。
我愿意接受任何其他建议,包括更改解析器。