If you’ve been using Reporting Services 2005 to generate MDX you’ll have probably noticed that the StrTo<Something> family of functions (StrToSet, StrToMember, StrToTuple, StrToValue) have gained an extra, optional parameter – the CONSTRAINED flag. It’s not mentioned in Books Online and since someone has been asking about it on the newsgroup I thought it would be worth a quick post explaining what it does.
Basically it’s a security feature for middle-tier scenarios to stop MDX injection attacks. Running parameterised MDX queries in RS is probably going to be the most common example of when you’d want to use it, but I guess anywhere where you are generating dynamic MDX in code you’re running the risk of an evil user trying to pass you a stored procedure call (or something worse) instead of the member name or key you were expecting. By putting the CONSTRAINED flag in your query you automatically restrict what the StrTo<Something> functions can accept as their first parameter:
- StrToMember can only take a string containing a member name
- StrToSet can only take an explicitly defined set, ie a list of member names or tuples in curly brackets
- StrToTuple can only take an explicitly defined tuple, ie a list of member names in brackets
- StrToValue can only take a constant value
What’s not allowed with CONSTRAINED is an MDX expression which evaluates to either a Member, Set, Tuple or Value. Here’s an Adventure Works query which illustrates this:
WITH
MEMBER
MEASURES.STRTOSET_TEST1 AS COUNT(STRTOSET("{[Measures].[Internet Order Quantity]}"))MEMBER
MEASURES.STRTOSET_TEST2 AS COUNT(STRTOSET("MEASURES.MEMBERS"))MEMBER
MEASURES.STRTOSET_TEST3 AS COUNT(STRTOSET("{[Measures].[Internet Order Quantity]}", CONSTRAINED))MEMBER
MEASURES.STRTOSET_TEST4 AS COUNT(STRTOSET("MEASURES.MEMBERS", CONSTRAINED))SELECT
{MEASURES.STRTOSET_TEST1, MEASURES.STRTOSET_TEST2, MEASURES.STRTOSET_TEST3, MEASURES.STRTOSET_TEST4} ON 0FROM
[ADVENTURE WORKS]
The final calculated member here produces an error because "MEASURES.MEMBERS" is an expression which evaluates to a set and is not an explicitly defined set like the ones in the first or third calculated members.
UPDATE: Jon makes a good point in the comments…