Skip to content

Commit

Permalink
Do not interpolate literals when prepared=true.
Browse files Browse the repository at this point in the history
This addresses doug-martin#132

It is a reset of closed PR: doug-martin#151

The gist of this fix is to modify the builders to not interpolate
nil and boolean values so that prepared statements can work properly.
This makes prepared=true work more consistently across all types.

The scope of this change:

(1) Modify literalNil to use a placeholder if prepared=true similar to
literalBool and literalInt

(2) Modify checkBoolExpType to not turn (in)equality on nil or bool
values to an IS expression.

(3) LOTS of tests and examples updated to reflect the new behavior.

(4) Fix bugs from doug-martin#151 found by
@doug-martin to preserve correct behavior with Is/IsNot and not
incorrectly map them to Eq/NotEq.
  • Loading branch information
Marshall McMullen committed Sep 10, 2019
1 parent 67f00a5 commit 8d88108
Show file tree
Hide file tree
Showing 20 changed files with 180 additions and 183 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ fmt.Println(sql)

Output:
```
DELETE FROM "test" WHERE ("c" IS NULL)
DELETE FROM "test" WHERE ("c" = NULL)
```

<a name="contributions"></a>
Expand Down
16 changes: 8 additions & 8 deletions database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,18 @@ func (ds *databaseSuite) TestScanVal() {
func (ds *databaseSuite) TestExec() {
mDb, mock, err := sqlmock.New()
ds.NoError(err)
mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" = NULL\)`).
WithArgs().
WillReturnResult(sqlmock.NewResult(0, 0))

mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" = NULL\)`).
WithArgs().
WillReturnError(errors.New("mock error"))

db := New("mock", mDb)
_, err = db.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
_, err = db.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" = NULL)`)
ds.NoError(err)
_, err = db.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
_, err = db.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" = NULL)`)
ds.EqualError(err, "goqu: mock error")
}

Expand Down Expand Up @@ -569,20 +569,20 @@ func (tds *txdatabaseSuite) TestExec() {
mDb, mock, err := sqlmock.New()
tds.NoError(err)
mock.ExpectBegin()
mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" = NULL\)`).
WithArgs().
WillReturnResult(sqlmock.NewResult(0, 0))

mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" = NULL\)`).
WithArgs().
WillReturnError(errors.New("mock error"))
mock.ExpectCommit()
db := newDatabase("mock", mDb)
tx, err := db.Begin()
tds.NoError(err)
_, err = tx.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
_, err = tx.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" = NULL)`)
tds.NoError(err)
_, err = tx.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
_, err = tx.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" = NULL)`)
tds.EqualError(err, "goqu: mock error")
tds.NoError(tx.Commit())
}
Expand Down
16 changes: 8 additions & 8 deletions delete_dataset_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ func ExampleDeleteDataset_Where() {
).ToSQL()
fmt.Println(sql)
// Output:
// DELETE FROM "test" WHERE (("a" > 10) AND ("b" < 10) AND ("c" IS NULL) AND ("d" IN ('a', 'b', 'c')))
// DELETE FROM "test" WHERE (("a" > 10) OR ("b" < 10) OR ("c" IS NULL) OR ("d" IN ('a', 'b', 'c')))
// DELETE FROM "test" WHERE ((("a" > 10) AND ("b" < 10)) OR (("c" IS NULL) AND ("d" IN ('a', 'b', 'c'))))
// DELETE FROM "test" WHERE (("a" > 10) AND ("b" < 10) AND ("c" = NULL) AND ("d" IN ('a', 'b', 'c')))
// DELETE FROM "test" WHERE (("a" > 10) OR ("b" < 10) OR ("c" = NULL) OR ("d" IN ('a', 'b', 'c')))
// DELETE FROM "test" WHERE ((("a" > 10) AND ("b" < 10)) OR (("c" = NULL) AND ("d" IN ('a', 'b', 'c'))))
// DELETE FROM "test" WHERE (("a" > 10) AND ("b" < 10) AND ("c" IS NULL) AND ("d" IN ('a', 'b', 'c')))
// DELETE FROM "test" WHERE (("a" > 10) OR (("b" < 10) AND ("c" IS NULL)))
}
Expand Down Expand Up @@ -186,11 +186,11 @@ func ExampleDeleteDataset_Where_prepared() {
).ToSQL()
fmt.Println(sql, args)
// Output:
// DELETE FROM "test" WHERE (("a" > ?) AND ("b" < ?) AND ("c" IS NULL) AND ("d" IN (?, ?, ?))) [10 10 a b c]
// DELETE FROM "test" WHERE (("a" > ?) OR ("b" < ?) OR ("c" IS NULL) OR ("d" IN (?, ?, ?))) [10 10 a b c]
// DELETE FROM "test" WHERE ((("a" > ?) AND ("b" < ?)) OR (("c" IS NULL) AND ("d" IN (?, ?, ?)))) [10 10 a b c]
// DELETE FROM "test" WHERE (("a" > ?) AND ("b" < ?) AND ("c" IS NULL) AND ("d" IN (?, ?, ?))) [10 10 a b c]
// DELETE FROM "test" WHERE (("a" > ?) OR (("b" < ?) AND ("c" IS NULL))) [10 10]
// DELETE FROM "test" WHERE (("a" > ?) AND ("b" < ?) AND ("c" = ?) AND ("d" IN (?, ?, ?))) [10 10 <nil> a b c]
// DELETE FROM "test" WHERE (("a" > ?) OR ("b" < ?) OR ("c" = ?) OR ("d" IN (?, ?, ?))) [10 10 <nil> a b c]
// DELETE FROM "test" WHERE ((("a" > ?) AND ("b" < ?)) OR (("c" = ?) AND ("d" IN (?, ?, ?)))) [10 10 <nil> a b c]
// DELETE FROM "test" WHERE (("a" > ?) AND ("b" < ?) AND ("c" IS ?) AND ("d" IN (?, ?, ?))) [10 10 <nil> a b c]
// DELETE FROM "test" WHERE (("a" > ?) OR (("b" < ?) AND ("c" IS ?))) [10 10 <nil>]
}

func ExampleDeleteDataset_ClearWhere() {
Expand Down
2 changes: 0 additions & 2 deletions dialect/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ func DialectOptions() *goqu.SQLDialectOptions {
opts.IncludePlaceholderNum = false
opts.QuoteRune = '`'
opts.DefaultValuesFragment = []byte("")
opts.True = []byte("1")
opts.False = []byte("0")
opts.TimeFormat = "2006-01-02 15:04:05"
opts.BooleanOperatorLookup = map[exp.BooleanOperation][]byte{
exp.EqOp: []byte("="),
Expand Down
8 changes: 4 additions & 4 deletions dialect/mysql/mysql_dialect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ func (mds *mysqlDialectSuite) TestBooleanOperations() {
ds := mds.GetDs("test")
sql, _, err := ds.Where(col.Eq(true)).ToSQL()
mds.NoError(err)
mds.Equal("SELECT * FROM `test` WHERE (`a` IS TRUE)", sql)
mds.Equal("SELECT * FROM `test` WHERE (`a` = TRUE)", sql)
sql, _, err = ds.Where(col.Eq(false)).ToSQL()
mds.NoError(err)
mds.Equal("SELECT * FROM `test` WHERE (`a` IS FALSE)", sql)
mds.Equal("SELECT * FROM `test` WHERE (`a` = FALSE)", sql)
sql, _, err = ds.Where(col.Is(true)).ToSQL()
mds.NoError(err)
mds.Equal("SELECT * FROM `test` WHERE (`a` IS TRUE)", sql)
Expand All @@ -123,10 +123,10 @@ func (mds *mysqlDialectSuite) TestBooleanOperations() {

sql, _, err = ds.Where(col.Neq(true)).ToSQL()
mds.NoError(err)
mds.Equal("SELECT * FROM `test` WHERE (`a` IS NOT TRUE)", sql)
mds.Equal("SELECT * FROM `test` WHERE (`a` != TRUE)", sql)
sql, _, err = ds.Where(col.Neq(false)).ToSQL()
mds.NoError(err)
mds.Equal("SELECT * FROM `test` WHERE (`a` IS NOT FALSE)", sql)
mds.Equal("SELECT * FROM `test` WHERE (`a` != FALSE)", sql)
sql, _, err = ds.Where(col.IsNot(true)).ToSQL()
mds.NoError(err)
mds.Equal("SELECT * FROM `test` WHERE (`a` IS NOT TRUE)", sql)
Expand Down
8 changes: 4 additions & 4 deletions dialect/sqlite3/sqlite3_dialect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ func (sds *sqlite3DialectSuite) TestBooleanOperations() {
ds := sds.GetDs("test")
sql, _, err := ds.Where(goqu.C("a").Eq(true)).ToSQL()
sds.NoError(err)
sds.Equal("SELECT * FROM `test` WHERE (`a` IS 1)", sql)
sds.Equal("SELECT * FROM `test` WHERE (`a` = 1)", sql)
sql, _, err = ds.Where(goqu.C("a").Eq(false)).ToSQL()
sds.NoError(err)
sds.Equal("SELECT * FROM `test` WHERE (`a` IS 0)", sql)
sds.Equal("SELECT * FROM `test` WHERE (`a` = 0)", sql)
sql, _, err = ds.Where(goqu.C("a").Is(true)).ToSQL()
sds.NoError(err)
sds.Equal("SELECT * FROM `test` WHERE (`a` IS 1)", sql)
Expand All @@ -148,10 +148,10 @@ func (sds *sqlite3DialectSuite) TestBooleanOperations() {

sql, _, err = ds.Where(goqu.C("a").Neq(true)).ToSQL()
sds.NoError(err)
sds.Equal("SELECT * FROM `test` WHERE (`a` IS NOT 1)", sql)
sds.Equal("SELECT * FROM `test` WHERE (`a` != 1)", sql)
sql, _, err = ds.Where(goqu.C("a").Neq(false)).ToSQL()
sds.NoError(err)
sds.Equal("SELECT * FROM `test` WHERE (`a` IS NOT 0)", sql)
sds.Equal("SELECT * FROM `test` WHERE (`a` != 0)", sql)
sql, _, err = ds.Where(goqu.C("a").IsNot(true)).ToSQL()
sds.NoError(err)
sds.Equal("SELECT * FROM `test` WHERE (`a` IS NOT 1)", sql)
Expand Down
4 changes: 2 additions & 2 deletions docs/deleting.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ fmt.Println(sql)

Output:
```
DELETE FROM "test" WHERE (("a" > ?) AND ("b" < ?) AND ("c" IS NULL) AND ("d" IN (?, ?, ?))) [10 10 a b c]
DELETE FROM "test" WHERE (("a" > ?) AND ("b" < ?) AND ("c" = NULL) AND ("d" IN (?, ?, ?))) [10 10 a b c]
```

<a name="where"></a>
Expand All @@ -136,7 +136,7 @@ fmt.Println(sql)

Output:
```
DELETE FROM "test" WHERE (("a" > 10) AND ("b" < 10) AND ("c" IS NULL) AND ("d" IN ('a', 'b', 'c')))
DELETE FROM "test" WHERE (("a" > 10) AND ("b" < 10) AND ("c" = NULL) AND ("d" IN ('a', 'b', 'c')))
```

<a name="order"></a>
Expand Down
58 changes: 29 additions & 29 deletions docs/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
* [`C`](#C) - An Identifier that represents a Column. See the docs for more examples
* [`I`](#I) - An Identifier represents a schema, table, or column or any combination. I parses identifiers seperated by a . character.
* [`L`](#L) - An SQL literal.
* [`V`](#V) - An Value to be used in SQL.
* [`V`](#V) - An Value to be used in SQL.
* [`And`](#and) - AND multiple expressions together.
* [`Or`](#or) - OR multiple expressions together.
* [Complex Example] - Complex Example using most of the Expression DSL.

The entry points for expressions are:

<a name="ex"></a>
**[`Ex{}`](https://godoc.org/github.com/doug-martin/goqu#Ex)**
**[`Ex{}`](https://godoc.org/github.com/doug-martin/goqu#Ex)**

A map where the key will become an Identifier and the Key is the value, this is most commonly used in the Where clause. By default `Ex` will use the equality operator except in cases where the equality operator will not work, see the example below.

Expand All @@ -35,7 +35,7 @@ fmt.Println(sql)

Output:
```sql
SELECT * FROM "items" WHERE (("col1" = 'a') AND ("col2" = 1) AND ("col3" IS TRUE) AND ("col4" IS FALSE) AND ("col5" IS NULL) AND ("col6" IN ('a', 'b', 'c')))
SELECT * FROM "items" WHERE (("col1" = 'a') AND ("col2" = 1) AND ("col3" = TRUE) AND ("col4" = FALSE) AND ("col5" = NULL) AND ("col6" IN ('a', 'b', 'c')))
```

You can also use the [`Op`](https://godoc.org/github.com/doug-martin/goqu#Op) map which allows you to create more complex expressions using the map syntax. When using the `Op` map the key is the name of the comparison you want to make (e.g. `"neq"`, `"like"`, `"is"`, `"in"`), the key is case insensitive.
Expand All @@ -51,12 +51,12 @@ fmt.Println(sql)

Output:
```sql
SELECT * FROM "items" WHERE (("col1" != 'a') AND ("col3" IS NOT TRUE) AND ("col6" NOT IN ('a', 'b', 'c')))
SELECT * FROM "items" WHERE (("col1" != 'a') AND ("col3" != TRUE) AND ("col6" NOT IN ('a', 'b', 'c')))
```
For a more complete examples see the [`Op`](https://godoc.org/github.com/doug-martin/goqu#Op) and [`Ex`](https://godoc.org/github.com/doug-martin/goqu#Ex) docs

<a name="ex-or"></a>
**[`ExOr{}`](https://godoc.org/github.com/doug-martin/goqu#ExOr)**
**[`ExOr{}`](https://godoc.org/github.com/doug-martin/goqu#ExOr)**

A map where the key will become an Identifier and the Key is the value, this is most commonly used in the Where clause. By default `ExOr` will use the equality operator except in cases where the equality operator will not work, see the example below.

Expand All @@ -71,14 +71,14 @@ sql, _, _ := db.From("items").Where(goqu.ExOr{
}).ToSQL()
fmt.Println(sql)
```

Output:
```sql
SELECT * FROM "items" WHERE (("col1" = 'a') OR ("col2" = 1) OR ("col3" IS TRUE) OR ("col4" IS FALSE) OR ("col5" IS NULL) OR ("col6" IN ('a', 'b', 'c')))
SELECT * FROM "items" WHERE (("col1" = 'a') OR ("col2" = 1) OR ("col3" = TRUE) OR ("col4" = FALSE) OR ("col5" = NULL) OR ("col6" IN ('a', 'b', 'c')))
```

You can also use the [`Op`](https://godoc.org/github.com/doug-martin/goqu#Op) map which allows you to create more complex expressions using the map syntax. When using the `Op` map the key is the name of the comparison you want to make (e.g. `"neq"`, `"like"`, `"is"`, `"in"`), the key is case insensitive.

```go
sql, _, _ := db.From("items").Where(goqu.ExOr{
"col1": goqu.Op{"neq": "a"},
Expand All @@ -87,10 +87,10 @@ sql, _, _ := db.From("items").Where(goqu.ExOr{
}).ToSQL()
fmt.Println(sql)
```

Output:
```sql
SELECT * FROM "items" WHERE (("col1" != 'a') OR ("col3" IS NOT TRUE) OR ("col6" NOT IN ('a', 'b', 'c')))
SELECT * FROM "items" WHERE (("col1" != 'a') OR ("col3" != TRUE) OR ("col6" NOT IN ('a', 'b', 'c')))
```
For a more complete examples see the [`Op`](https://godoc.org/github.com/doug-martin/goqu#Op) and [`ExOr`](https://godoc.org/github.com/doug-martin/goqu#Ex) docs

Expand All @@ -113,7 +113,7 @@ fmt.Println(sql)
```

<a name="T"></a>
**[`T()`](https://godoc.org/github.com/doug-martin/goqu#T)**
**[`T()`](https://godoc.org/github.com/doug-martin/goqu#T)**

An Identifier that represents a Table. With a Table identifier you can fully qualify columns.
```go
Expand All @@ -130,7 +130,7 @@ fmt.Println(sql)
```

<a name="C"></a>
**[`C()`](https://godoc.org/github.com/doug-martin/goqu#C)**
**[`C()`](https://godoc.org/github.com/doug-martin/goqu#C)**

An Identifier that represents a Column. See the [docs]((https://godoc.org/github.com/doug-martin/goqu#C)) for more examples

Expand All @@ -141,7 +141,7 @@ fmt.Println(sql)
```

<a name="I"></a>
**[`I()`](https://godoc.org/github.com/doug-martin/goqu#I)**
**[`I()`](https://godoc.org/github.com/doug-martin/goqu#I)**

An Identifier represents a schema, table, or column or any combination. `I` parses identifiers seperated by a `.` character.

Expand All @@ -157,7 +157,7 @@ goqu.I("col") == goqu.C("col")
```

<a name="L"></a>
**[`L()`](https://godoc.org/github.com/doug-martin/goqu#L)**
**[`L()`](https://godoc.org/github.com/doug-martin/goqu#L)**

An SQL literal. You may find yourself in a situation where an IdentifierExpression cannot expression an SQL fragment that your database supports. In that case you can use a LiteralExpression

Expand All @@ -171,17 +171,17 @@ goqu.L(`custom_func("a")`)
// postgres JSON access
goqu.L(`"json_col"->>'someField'`).As("some_field")
```
You can also use placeholders in your literal with a `?` character. `goqu` will handle changing it to what the dialect needs (e.g. `?` mysql, `$1` postgres, `?` sqlite3).

You can also use placeholders in your literal with a `?` character. `goqu` will handle changing it to what the dialect needs (e.g. `?` mysql, `$1` postgres, `?` sqlite3).

**NOTE** If your query is not prepared the placeholders will be properly interpolated.

```go
goqu.L("col IN (?, ?, ?)", "a", "b", "c")
goqu.L("col IN (?, ?, ?)", "a", "b", "c")
```

Putting it together

```go
ds := db.From("test").Where(
goqu.L(`("json"::TEXT = "other_json"::TEXT)`),
Expand All @@ -205,7 +205,7 @@ SELECT * FROM "test" WHERE ("json"::TEXT = "other_json"::TEXT) AND col IN ($1, $
<a name="V"></a>
**[`V()`](https://godoc.org/github.com/doug-martin/goqu#V)**

Sometimes you may have a value that you want to use directly in SQL.
Sometimes you may have a value that you want to use directly in SQL.

**NOTE** This is a shorter version of `goqu.L("?", val)`

Expand Down Expand Up @@ -258,7 +258,7 @@ SELECT * FROM "user" WHERE (? != ?) [1, 1]


<a name="and"></a>
**[`And()`](https://godoc.org/github.com/doug-martin/goqu#And)**
**[`And()`](https://godoc.org/github.com/doug-martin/goqu#And)**

You can use the `And` function to AND multiple expressions together.

Expand All @@ -285,7 +285,7 @@ SELECT * FROM "test" WHERE (("col" > ?) AND ("col" < ?)) [10 20]
```

<a name="or"></a>
**[`Or()`](https://godoc.org/github.com/doug-martin/goqu#Or)**
**[`Or()`](https://godoc.org/github.com/doug-martin/goqu#Or)**

You can use the `Or` function to OR multiple expressions together.

Expand All @@ -310,7 +310,7 @@ SELECT * FROM "test" WHERE (("col" = ?) OR ("col" = ?)) [10 20]
```

You can also use `Or` and `And` functions in tandem which will give you control not only over how the Expressions are joined together, but also how they are grouped

```go
ds := goqu.From("items").Where(
goqu.Or(
Expand Down Expand Up @@ -358,8 +358,8 @@ fmt.Println(sql, args)

Output:
```sql
SELECT * FROM "test" WHERE ((("col1" = 1) AND ("col2" IS TRUE)) OR (("col3" IS NULL) AND ("col4" = 'foo'))) []
SELECT * FROM "test" WHERE ((("col1" = ?) AND ("col2" IS TRUE)) OR (("col3" IS NULL) AND ("col4" = ?))) [1 foo]
SELECT * FROM "test" WHERE ((("col1" = 1) AND ("col2" = TRUE)) OR (("col3" = NULL) AND ("col4" = 'foo'))) []
SELECT * FROM "test" WHERE ((("col1" = ?) AND ("col2" = TRUE)) OR (("col3" = NULL) AND ("col4" = ?))) [1 foo]
```

<a name="complex"></a>
Expand Down Expand Up @@ -426,8 +426,8 @@ SELECT COUNT(*)
FROM "test"
INNER JOIN "test2" ON ("test"."fkey" = "test2"."id")
LEFT JOIN "test3" ON ("test2"."fkey" = "test3"."id")
WHERE ((("test"."name" ~ '^(a|b)') AND ("test2"."amount" IS NOT NULL)) AND
(("test3"."id" IS NULL) OR ("test3"."status" IN ('passed', 'active', 'registered'))))
WHERE ((("test"."name" ~ '^(a|b)') AND ("test2"."amount" != NULL)) AND
(("test3"."id" = NULL) OR ("test3"."status" IN ('passed', 'active', 'registered'))))
GROUP BY "test"."user_id"
HAVING (AVG("test3"."age") > 10)
ORDER BY "test"."created" DESC NULLS LAST []
Expand All @@ -437,8 +437,8 @@ SELECT COUNT(*)
FROM "test"
INNER JOIN "test2" ON ("test"."fkey" = "test2"."id")
LEFT JOIN "test3" ON ("test2"."fkey" = "test3"."id")
WHERE ((("test"."name" ~ ?) AND ("test2"."amount" IS NOT NULL)) AND
(("test3"."id" IS NULL) OR ("test3"."status" IN (?, ?, ?))))
WHERE ((("test"."name" ~ ?) AND ("test2"."amount" != NULL)) AND
(("test3"."id" = NULL) OR ("test3"."status" IN (?, ?, ?))))
GROUP BY "test"."user_id"
HAVING (AVG("test3"."age") > ?)
ORDER BY "test"."created" DESC NULLS LAST [^(a|b) passed active registered 10]
Expand Down
2 changes: 1 addition & 1 deletion docs/interpolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ sql, args, _ = preparedDs.
fmt.Println(sql, args)

// Output:
// SELECT * FROM "items" WHERE (("col1" = ?) AND ("col2" = ?) AND ("col3" IS TRUE) AND ("col4" IS FALSE) AND ("col5" IN (?, ?, ?))) [a 1 a b c]
// SELECT * FROM "items" WHERE (("col1" = ?) AND ("col2" = ?) AND ("col3" = TRUE) AND ("col4" = FALSE) AND ("col5" IN (?, ?, ?))) [a 1 a b c]
// INSERT INTO "items" ("address", "name") VALUES (?, ?), (?, ?) [111 Test Addr Test1 112 Test Addr Test2]
// UPDATE "items" SET "address"=?,"name"=? [111 Test Addr Test]
// DELETE FROM "items" WHERE ("id" > ?) [10]
Expand Down

0 comments on commit 8d88108

Please sign in to comment.