Skip to content

Commit ae36ce2

Browse files
mysql: support to infer type of a duplicated arg (#615)
Fix for issue with WHERE clause in mysql (old parser) does not parse a parameters type correctly in certain circumstances. Such as: `SELECT * FROM tablex WHERE (id = sqlc.arg(id) OR sqlc.arg(id) = 0);` This type of statement is a simple way to conditionally filter by input arg, so that you do not have to define a GetX and a GetXbyID. (This is a simplified example) In sqlc v1.4.0 the second id argument gets parsed and added to the params struct as `ID_2` but is not given a type. This causes compile-time errors. Because of the way parameters are parsed and added to the params struct this fix only works when you define the parameters as sqlc.args(x) not with `?` or `:x`. Co-authored-by: Jessica Bellon <10819486+JessTheBell@users.noreply.github.com> Co-authored-by: Kyle Conroy <kyle@conroy.org>
1 parent a53b27f commit ae36ce2

7 files changed

Lines changed: 130 additions & 0 deletions

File tree

internal/endtoend/testdata/mysql_dupl_param_name/go/db.go

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/mysql_dupl_param_name/go/models.go

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/mysql_dupl_param_name/go/query.sql.go

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* name: SelectUserArg :many */
2+
SELECT first_name from
3+
users where (sqlc.arg(id) = id OR sqlc.arg(id) = 0);
4+
5+
6+
7+
8+
/* The following do not work with current impl */
9+
10+
/* name: SelectUserColon :many */
11+
/* SELECT first_name from */
12+
/* users where (:id = id OR :id = 0); */
13+
14+
15+
/* name: SelectUserQuestion :many */
16+
/* SELECT first_name from */
17+
/* users where (? = id OR ? = 0); */
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE users (
2+
id integer NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
first_name varchar(255) NOT NULL,
4+
last_name varchar(255)
5+
) ENGINE=InnoDB;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "1",
3+
"packages": [
4+
{
5+
"name": "querytest",
6+
"path": "go",
7+
"schema": "schema.sql",
8+
"queries": "query.sql",
9+
"engine": "mysql"
10+
}
11+
]
12+
}

internal/mysql/gen.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ func (r *Result) GoQueries(settings config.CombinedSettings) []golang.Query {
127127

128128
structInfo := make([]structParams, len(query.Params))
129129
for i := range query.Params {
130+
qp := query.Params[i]
131+
if qp.Typ == "" {
132+
// if the param doesn't have a type, check to see if there is
133+
// another param with the same name that does have a type.
134+
// Because of the way params are parsed and named this only works for sqlc.arg(x) named params, not :x or ?
135+
func(ps []*Param) {
136+
for j := range ps {
137+
if ps[j].OriginalName == qp.OriginalName &&
138+
ps[j].Typ != "" {
139+
query.Params[i].Typ = ps[j].Typ
140+
}
141+
}
142+
}(query.Params)
143+
}
130144
structInfo[i] = structParams{
131145
originalName: query.Params[i].Name,
132146
goType: query.Params[i].Typ,

0 commit comments

Comments
 (0)