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;
|
string dataDir = amoServer.ServerProperties["DataDir"].Value;
|
||||||
if (dataDir.EndsWith("\\")) dataDir = dataDir.Substring(0, dataDir.Length - 1);
|
if (dataDir.EndsWith("\\")) dataDir = dataDir.Substring(0, dataDir.Length - 1);
|
||||||
string commandStatement = String.Format("SystemGetSubdirs '{0}'", dataDir);
|
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 = "";
|
string dbDir = "";
|
||||||
foreach (XmlNode row in rows)
|
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)
|
public static int FindRowCount(Microsoft.AnalysisServices.Core.Server server, string tableName, string databaseName)
|
||||||
{
|
{
|
||||||
string dax = String.Format("EVALUATE ROW( \"RowCount\", COUNTROWS('{0}'))", tableName);
|
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)
|
foreach (XmlNode row in rows)
|
||||||
{
|
{
|
||||||
@ -552,7 +553,7 @@ namespace BismNormalizer.TabularCompare.Core
|
|||||||
/// <param name="server"></param>
|
/// <param name="server"></param>
|
||||||
/// <param name="commandStatement"></param>
|
/// <param name="commandStatement"></param>
|
||||||
/// <returns>XmlNodeList containing results of the command execution.</returns>
|
/// <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);
|
XmlWriter xmlWriter = server.StartXmlaRequest(XmlaRequestType.Undefined);
|
||||||
WriteSoapEnvelopeWithCommandStatement(xmlWriter, server.SessionID, catalog, commandStatement);
|
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("myns1", "urn:schemas-microsoft-com:xml-analysis");
|
||||||
nsmgr.AddNamespace("myns2", "urn:schemas-microsoft-com:xml-analysis:rowset");
|
nsmgr.AddNamespace("myns2", "urn:schemas-microsoft-com:xml-analysis:rowset");
|
||||||
XmlNodeList rows = documentResponse.SelectNodes("//myns1:ExecuteResponse/myns1:return/myns2:root/myns2:row", nsmgr);
|
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;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ using Tom = Microsoft.AnalysisServices.Tabular;
|
|||||||
using Amo = Microsoft.AnalysisServices;
|
using Amo = Microsoft.AnalysisServices;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using BismNormalizer.TabularCompare.Core;
|
using BismNormalizer.TabularCompare.Core;
|
||||||
|
using System.Web.UI.WebControls.WebParts;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace BismNormalizer.TabularCompare.TabularMetadata
|
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
|
//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}");
|
throw new Amo.ConnectionException($"Could not connect to database {_connectionInfo.DatabaseName}");
|
||||||
}
|
}
|
||||||
InitializeCalcDependencies();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Shell model
|
//Shell model
|
||||||
@ -148,9 +149,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
|
|||||||
{
|
{
|
||||||
_cultures.Add(new Culture(this, culture));
|
_cultures.Add(new Culture(this, culture));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_connectionInfo.UseBimFile)
|
||||||
|
{
|
||||||
|
InitializeCalcDependenciesFromM();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InitializeCalcDependenciesFromServer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeCalcDependencies()
|
private void InitializeCalcDependenciesFromServer()
|
||||||
{
|
{
|
||||||
_calcDependencies.Clear();
|
_calcDependencies.Clear();
|
||||||
string command =
|
string command =
|
||||||
@ -159,8 +169,15 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
|
|||||||
"NOT (OBJECT_TYPE = REFERENCED_OBJECT_TYPE AND " +
|
"NOT (OBJECT_TYPE = REFERENCED_OBJECT_TYPE AND " +
|
||||||
" [TABLE] = REFERENCED_TABLE AND" +
|
" [TABLE] = REFERENCED_TABLE AND" +
|
||||||
" OBJECT = REFERENCED_OBJECT);"; //Ignore recursive M expression dependencies
|
" 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)
|
foreach (XmlNode row in rows)
|
||||||
{
|
{
|
||||||
string objectType = "";
|
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>
|
/// <summary>
|
||||||
/// Disconnect from the SSAS server.
|
/// Disconnect from the SSAS server.
|
||||||
|
Loading…
Reference in New Issue
Block a user