parse m expressions for dependencies
This commit is contained in:
parent
353bab30c5
commit
f884719731
@ -576,7 +576,8 @@ namespace BismNormalizer.TabularCompare
|
||||
string dataDir = amoServer.ServerProperties["DataDir"].Value;
|
||||
if (dataDir.EndsWith("\\")) dataDir = dataDir.Substring(0, dataDir.Length - 1);
|
||||
string commandStatement = String.Format("SystemGetSubdirs '{0}'", dataDir);
|
||||
XmlNodeList rows = Core.Comparison.ExecuteXmlaCommand(amoServer, "", commandStatement);
|
||||
bool foundFault = false;
|
||||
XmlNodeList rows = Core.Comparison.ExecuteXmlaCommand(amoServer, "", commandStatement, ref foundFault);
|
||||
|
||||
string dbDir = "";
|
||||
foreach (XmlNode row in rows)
|
||||
|
@ -522,7 +522,8 @@ namespace BismNormalizer.TabularCompare.Core
|
||||
public static int FindRowCount(Microsoft.AnalysisServices.Core.Server server, string tableName, string databaseName)
|
||||
{
|
||||
string dax = String.Format("EVALUATE ROW( \"RowCount\", COUNTROWS('{0}'))", tableName);
|
||||
XmlNodeList rows = ExecuteXmlaCommand(server, databaseName, dax);
|
||||
bool foundFault = false;
|
||||
XmlNodeList rows = ExecuteXmlaCommand(server, databaseName, dax, ref foundFault);
|
||||
|
||||
foreach (XmlNode row in rows)
|
||||
{
|
||||
@ -552,7 +553,7 @@ namespace BismNormalizer.TabularCompare.Core
|
||||
/// <param name="server"></param>
|
||||
/// <param name="commandStatement"></param>
|
||||
/// <returns>XmlNodeList containing results of the command execution.</returns>
|
||||
public static XmlNodeList ExecuteXmlaCommand(Microsoft.AnalysisServices.Core.Server server, string catalog, string commandStatement)
|
||||
public static XmlNodeList ExecuteXmlaCommand(Microsoft.AnalysisServices.Core.Server server, string catalog, string commandStatement, ref bool foundFault)
|
||||
{
|
||||
XmlWriter xmlWriter = server.StartXmlaRequest(XmlaRequestType.Undefined);
|
||||
WriteSoapEnvelopeWithCommandStatement(xmlWriter, server.SessionID, catalog, commandStatement);
|
||||
@ -567,6 +568,12 @@ namespace BismNormalizer.TabularCompare.Core
|
||||
nsmgr.AddNamespace("myns1", "urn:schemas-microsoft-com:xml-analysis");
|
||||
nsmgr.AddNamespace("myns2", "urn:schemas-microsoft-com:xml-analysis:rowset");
|
||||
XmlNodeList rows = documentResponse.SelectNodes("//myns1:ExecuteResponse/myns1:return/myns2:root/myns2:row", nsmgr);
|
||||
|
||||
if (rows.Count == 0 && documentResponse.GetElementsByTagName("faultcode").Count > 0)
|
||||
{
|
||||
foundFault = true;
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ using Tom = Microsoft.AnalysisServices.Tabular;
|
||||
using Amo = Microsoft.AnalysisServices;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using BismNormalizer.TabularCompare.Core;
|
||||
using System.Web.UI.WebControls.WebParts;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BismNormalizer.TabularCompare.TabularMetadata
|
||||
{
|
||||
@ -72,7 +74,6 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
|
||||
//Don't need try to load from project here as will already be done before instantiated Comparison
|
||||
throw new Amo.ConnectionException($"Could not connect to database {_connectionInfo.DatabaseName}");
|
||||
}
|
||||
InitializeCalcDependencies();
|
||||
}
|
||||
|
||||
//Shell model
|
||||
@ -148,9 +149,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
|
||||
{
|
||||
_cultures.Add(new Culture(this, culture));
|
||||
}
|
||||
|
||||
if (_connectionInfo.UseBimFile)
|
||||
{
|
||||
InitializeCalcDependenciesFromM();
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeCalcDependenciesFromServer();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeCalcDependencies()
|
||||
private void InitializeCalcDependenciesFromServer()
|
||||
{
|
||||
_calcDependencies.Clear();
|
||||
string command =
|
||||
@ -159,8 +169,15 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
|
||||
"NOT (OBJECT_TYPE = REFERENCED_OBJECT_TYPE AND " +
|
||||
" [TABLE] = REFERENCED_TABLE AND" +
|
||||
" OBJECT = REFERENCED_OBJECT);"; //Ignore recursive M expression dependencies
|
||||
XmlNodeList rows = Core.Comparison.ExecuteXmlaCommand(_server, _connectionInfo.DatabaseName, command);
|
||||
bool foundFault = false;
|
||||
XmlNodeList rows = Core.Comparison.ExecuteXmlaCommand(_server, _connectionInfo.DatabaseName, command, ref foundFault);
|
||||
|
||||
if (foundFault)
|
||||
{
|
||||
InitializeCalcDependenciesFromM();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (XmlNode row in rows)
|
||||
{
|
||||
string objectType = "";
|
||||
@ -197,6 +214,131 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct MObject
|
||||
{
|
||||
public string ObjectType;
|
||||
public string TableName;
|
||||
public string ObjectName;
|
||||
public string Expression;
|
||||
|
||||
public MObject(string objectType, string tableName, string objectName, string expression)
|
||||
{
|
||||
ObjectType = objectType;
|
||||
TableName = tableName;
|
||||
ObjectName = objectName;
|
||||
Expression = expression;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeCalcDependenciesFromM()
|
||||
{
|
||||
//TODO: Doesn't deal with structured data sources (DSRs) yet
|
||||
|
||||
_calcDependencies.Clear();
|
||||
List<MObject> mObjects = new List<MObject>();
|
||||
|
||||
//Add table partitions to mObjects collection
|
||||
foreach (Table table in _tables)
|
||||
{
|
||||
foreach (Partition partition in table.TomTable.Partitions)
|
||||
{
|
||||
if (partition.SourceType == PartitionSourceType.M)
|
||||
{
|
||||
mObjects.Add(
|
||||
new MObject(
|
||||
objectType: "PARTITION",
|
||||
tableName: table.Name,
|
||||
objectName: partition.Name,
|
||||
expression: ((MPartitionSource)partition.Source).Expression
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Add other M expressions to mObjects collection
|
||||
foreach (Expression expression in _expressions)
|
||||
{
|
||||
mObjects.Add(
|
||||
new MObject(
|
||||
objectType: "M_EXPRESSION",
|
||||
tableName: "",
|
||||
objectName: expression.Name,
|
||||
expression: expression.TomExpression.Expression
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
char[] delimiterChars = { ' ', ',', ':', '\t', '\n', '[', ']', '(', ')', '{', '}' };
|
||||
List<string> keywords = new List<string>() { "let", "in" }; //TODO: need list of all M keywords
|
||||
|
||||
foreach (MObject mObject in mObjects)
|
||||
{
|
||||
string regex = "(#\"(.*?)\")";
|
||||
//Expression with double quote references removed
|
||||
string expressionRegex = Regex.Replace(mObject.Expression, regex, "");
|
||||
string[] words = expressionRegex.Split(delimiterChars);
|
||||
|
||||
foreach (MObject referencedMObject in mObjects)
|
||||
{
|
||||
bool foundDependency = false;
|
||||
|
||||
if (!( //Ignore circular dependencies
|
||||
mObject.ObjectName == referencedMObject.ObjectName &&
|
||||
mObject.ObjectType == referencedMObject.ObjectType &&
|
||||
mObject.TableName == referencedMObject.TableName
|
||||
))
|
||||
{
|
||||
if ( //if M_EXPRESSION name contains spaces or is a keyword, only need to check for occurrence like #"My Query" or #"let"
|
||||
(referencedMObject.ObjectType == "M_EXPRESSION" && (referencedMObject.ObjectName.Contains(" ") || keywords.Contains(referencedMObject.ObjectName))) &&
|
||||
(mObject.Expression.Contains("\"" + referencedMObject.ObjectName + "\""))
|
||||
)
|
||||
{
|
||||
foundDependency = true;
|
||||
}
|
||||
else if ( //if table name contains spaces or is a keyword, only need to check for occurrence like #"My Query" or #"let"
|
||||
(referencedMObject.ObjectType == "PARTITION" && (referencedMObject.TableName.Contains(" ") || keywords.Contains(referencedMObject.TableName))) &&
|
||||
(mObject.Expression.Contains("\"" + referencedMObject.TableName + "\""))
|
||||
)
|
||||
{
|
||||
foundDependency = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string word in words)
|
||||
{
|
||||
if (
|
||||
(referencedMObject.ObjectType == "M_EXPRESSION" && word == referencedMObject.ObjectName && !keywords.Contains(referencedMObject.ObjectName)) ||
|
||||
(referencedMObject.ObjectType == "PARTITION" && word == referencedMObject.TableName && !keywords.Contains(referencedMObject.TableName))
|
||||
)
|
||||
{
|
||||
foundDependency = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDependency)
|
||||
{
|
||||
_calcDependencies.Add(
|
||||
new CalcDependency(
|
||||
this,
|
||||
objectType: mObject.ObjectType,
|
||||
tableName: mObject.TableName,
|
||||
objectName: mObject.ObjectName,
|
||||
expression: mObject.Expression,
|
||||
referencedObjectType: referencedMObject.ObjectType,
|
||||
referencedTableName: referencedMObject.TableName,
|
||||
referencedObjectName: referencedMObject.ObjectName,
|
||||
referencedExpression: referencedMObject.Expression
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the SSAS server.
|
||||
|
Loading…
Reference in New Issue
Block a user