Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Cosmos DB exception when using headers and query binding expressions #354

Closed

Conversation

anthonychu
Copy link
Member

@anthonychu anthonychu commented Dec 27, 2017

Currently this exception occurs when trying to use binding expressions that access headers and query from the HTTP trigger in Azure Functions:

"sqlQuery": "select * from c where c.id = {headers.foo}"

Microsoft.Azure.WebJobs.Host: Error while accessing 'foo': property doesn't exist.

{
string sqlToken = GetSqlParameterName(fullToken);
paramCollection.Add(new SqlParameter(sqlToken, item.Value));
tokens.Add(item.Key, sqlToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic seems duplicated from the other above, could they be encapsulated in a helper method to avoid some future break by an edit that forgets the update both?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored out the duplicate logic. Hope I didn't make it worse. 😄

@ealsur ealsur requested a review from brettsam January 2, 2018 19:50
object tokenObject = bindingData[token];
if (tokenObject is string tokenString)
{
string sqlToken = GetSqlParameterName(token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case seems like a subset of the other in terms of logic, just thinking out loud, but what if we had a single logic that created the replacements and the difference is that when the param is a string we are sending an input Dictionary of 1 item? Probably @brettsam has a more valuable feedback 😄

Copy link
Member

@ealsur ealsur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding comments

@ealsur
Copy link
Member

ealsur commented Jan 2, 2018

@brettsam I added you since you have probably more insight on the bindings

@brettsam
Copy link
Member

brettsam commented Jan 2, 2018

Hey @MikeStall -- I'm taking a look at this as well, but do we have some re-usable logic for parsing out nested property values?

Edit -- n/m -- I think it's up to the ResolutionPolicy to handle it all itself here, which makes sense.

private string GetSqlParameterName(string name)
{
const string safeSeparator = "_";
return "@" + name.Replace(".", safeSeparator).Replace("-", safeSeparator);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these not allowed in SqlParameter names? Is the list larger than this, or is it just these two characters? When doing replacements like this, I worry that we could stomp over another matching token. Even if it's rare, I wonder if there's another way to handle it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ealsur do you know the complete naming rules for the parameters?

Good point. We can generate something like a GUID for the name to avoid clobbering an existing token. If we do that, as long as it fits under the length limit for a parameter name, it should work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anthonychu Sorry, I missed this for some reason, never saw the notification :( Regarding the rules, I'm not really familiar with all of them but this one looks complete.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. So I guess Cosmos DB follows SQL rules for param names? Perhaps switching to a GUID is a safer way to go. I'll see if I can do that.

@@ -52,5 +52,30 @@ public void TemplateBind_DuplicateParameters()
Assert.Single(resolvedAttribute.SqlQueryParameters, p => p.Name == "@foo" && p.Value.ToString() == "1234");
Assert.Equal("SELECT * FROM c WHERE c.id = @foo AND c.value = @foo", result);
}

[Fact]
public void TemplateBind_NestedParameter()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see a test that includes both a nested and a non-nested parameter in the same SqlQuery. You should be able to add something here to check that as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@anthonychu
Copy link
Member Author

@brettsam @MikeStall I think this binding illustrates the need for a bit more information from the BindingTemplate. Instead of just the parameter names, it would be nice to be able to iterate over param/token objects that contain info such as the original parameter expression.

@anthonychu
Copy link
Member Author

@brettsam @ealsur Anything I can do to help move this PR along? Thanks.

@anthonychu
Copy link
Member Author

@brettsam @ealsur Updated to use GUIDs for parameter names to avoid conflicts. Only doing this for nested parameters. Existing behavior should stay the same to avoid accidental breaking changes.

@brettsam
Copy link
Member

Sorry this fell off my radar! I don't think this is going to tackle all the scenarios that it should, due to the lack of a good API for resolving the template tokens. This works great for headers, but from some of our other code I see that we also support things like JObject which this won't support. Let me follow up offline to see what we can do to reduce some of the code that we need here.

@brettsam
Copy link
Member

I'm going to go ahead and close this until we can come back with a fix that works for all dotted-notation. See Azure/azure-webjobs-sdk#1726 for the issue being tracked.

@brettsam brettsam closed this Aug 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants