Skip to content

Conversation

reltuk
Copy link
Contributor

@reltuk reltuk commented Nov 6, 2020

No description provided.

@reltuk reltuk requested a review from zachmu November 6, 2020 21:12
@CLAassistant
Copy link

CLAassistant commented Nov 6, 2020

CLA assistant check
All committers have signed the CLA.

@reltuk reltuk force-pushed the aaron/support-prepared-statements branch from 1f4ec38 to 0a0af60 Compare November 6, 2020 21:13
@reltuk
Copy link
Contributor Author

reltuk commented Nov 6, 2020

@zachmu Looking for a quick pass and any thoughts here. Approach:

  1. In StmtPrepare, give the query to the Analyzer and return the Schema() fields from the fully analyzed query.

  2. In StmtExecute, give the query to the parser, replace all the expression nodes of type BindVar with expression.NewLiteral nodes for the incoming bindings, give the resulting parse tree to the Analyzer, run the query as normal. Currently we re-analyze the queries because the types of the replaced expression nodes might affect analysis, and those can change from Execute to Execute.

  3. bindingsToSql is a little bit sad, but I think the approach is necessary and reasonable. For the most part, chooses to create the widest possible type instances of the incoming values.

Currently think that testing strategy here is going to be:

  1. Add some parse / plan tests for new BindVar nodes.
  2. Add some unit tests for ApplyBindings.
  3. Add some engine tests that use QueryWithBindings, probably along the lines of existing Query, Delete, Update, Insert tests.
  4. When we update Dolt to pick up these changes, add some cases to existing client connector tests to hit prepared statements as well.

Does that seem reasonable?

Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

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

Looks like a good approach!

@@ -1786,7 +1786,7 @@ func convertVal(v *sqlparser.SQLVal) (sql.Expression, error) {
}
return expression.NewLiteral(val, sql.LongBlob), nil
case sqlparser.ValArg:
return expression.NewLiteral(string(v.Val), sql.LongText), nil
return expression.NewBindVar(strings.TrimPrefix(string(v.Val), ":")), nil
Copy link
Member

Choose a reason for hiding this comment

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

Do named bindvars need to be distinct? If so, need an analyzer func to check that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, they're also support for a different syntax, SELECT * FROM test WHERE id = :id, and the identifier id could be used multiple times in the query. IDs are auto-assigned by the tokenizer for the ? syntax though, and those are distinct.

There's a problem though. The parser will parse a query that uses both ? and :name style variables and with the current approach it will run into a conflict if someone names one of their vars :v1, for example. Longer-term we should distinguish between the two types of variables in the parser I think.

Copy link
Member

Choose a reason for hiding this comment

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

Should have a few engine tests for the named var bindings in that case

Copy link
Member

Choose a reason for hiding this comment

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

Including tests of using the same named binvar multiple places in the same query, and trying to execute with named bindvars that aren't in the original query (I can't remember seeing tests of the latter, definitely need engine tests of the former)

if err != nil {
return nil, err
}
switch {
Copy link
Member

Choose a reason for hiding this comment

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

Seems like these would be better expressed as a switch on v.Type(), no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, maybe...I was using a few expressions like sqltypes.IsUnsigned(v.Type()), so I went with this approach...could change it or split it into two groups...

Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

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

Generally looks good, got a couple requests for more tests and a very annoying request to not add a nil struct param to every QueryTest struct, sorry.

I don't think we need to support subqueries in v1.

@@ -1786,7 +1786,7 @@ func convertVal(v *sqlparser.SQLVal) (sql.Expression, error) {
}
return expression.NewLiteral(val, sql.LongBlob), nil
case sqlparser.ValArg:
return expression.NewLiteral(string(v.Val), sql.LongText), nil
return expression.NewBindVar(strings.TrimPrefix(string(v.Val), ":")), nil
Copy link
Member

Choose a reason for hiding this comment

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

Should have a few engine tests for the named var bindings in that case

@@ -1786,7 +1786,7 @@ func convertVal(v *sqlparser.SQLVal) (sql.Expression, error) {
}
return expression.NewLiteral(val, sql.LongBlob), nil
case sqlparser.ValArg:
return expression.NewLiteral(string(v.Val), sql.LongText), nil
return expression.NewBindVar(strings.TrimPrefix(string(v.Val), ":")), nil
Copy link
Member

Choose a reason for hiding this comment

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

Including tests of using the same named binvar multiple places in the same query, and trying to execute with named bindvars that aren't in the original query (I can't remember seeing tests of the latter, definitely need engine tests of the former)

@reltuk reltuk marked this pull request as ready for review November 11, 2020 00:51
Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

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

Still don't see an engine test for applying the same named bindvar more than once in a query. Otherwise LGTM!

@reltuk reltuk merged commit d00e294 into master Nov 11, 2020
@Hydrocharged Hydrocharged deleted the aaron/support-prepared-statements branch December 3, 2020 10:01
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