Something that I have been thinking about lately is how you can write stored procedures that use Dynamic SQL with user-supplied text and still be safe and secure. The previous post on Dynamic SQL "Levels" covers much of my thinking on this, but I had some related ideas today that I wanted to get down also.
Use Case 1: The archetypical use-case for dynamic SQL using user or client supplied text is the "Dynamic Report" scenario, wherein the use specifies a table (or view) to report on, the columns (and column order), selection criteria and sorting.
Use Case 2: Additional complications to Use Case #1, might include functions, operators or expressions based on columns.
Thoughts: The columns in (1) should be manageable through Level 1 transformations. Likewise the sorting. The overall query structure would be set by the particular stored procedure called.
The match criteria are slightly more difficult, and are usually handled with a fixed AND clause type of syntax like:
"Operand1 Operator1 Operand2 [Operator2 Operand3]"
Where the Operands and Operators are passed by the client. The operators can be validated with Level 1 techniques, and the operators could be validated from a specific Operator List table. Call this the "Single Template" method.
Allowing more flexibilty is complicated, but could be handled by a "template and substiution" approach, where the client would pass a table of criteria like this:
Create Table #MatchClauses(
ClauseText NVarchar(255),
Subs1,
Subs2,
.... (up to 5?)
)
"AND @1 @2 @3", "C:col1", "O:<", "L:'Jones'"
Here, the embedded parameters are inteneded to be replaced, in order, by the passed parameter values. The passed parameters are encoded with their "Type" (C=column name, O=operator, L=literal value). Then the following table colud be defined to validate it:
Create Table MatchTemplates(
TemplateID int,
TemplateText NVarchar(255)
)
Create Table MatchTemplateSubs(
TemplateID int,
SubsNumber int,
AllowColumns bit,
AllowOperators bit,
AllowLiterals bit,
...
)
So that a table of pre-defined allowable Match templates could be used to transform the user text into lower level dynamic SQL.
The real exciting promise of this approach is to make one of the substitution types be (X:= expression) which could then substitute other MatchTemplate expressions or special ExpressionTemplates. This would allow the client to specify "nested" query expressions.
The difficulty of this is that the client woudl have to take some kind of input form the user and then transform it into a strict post-op or pre-op form and then construct the complicated strings and calling sequence from that. Fortunately, client code is good at custom parsing (unlike SQL).