Merge pull request #189 from huandu/feature/limit-offset-using-args

Fix #186: use args in LIMIT and/or OFFSET expression
This commit is contained in:
Huan Du
2025-02-11 15:11:22 +08:00
committed by GitHub
10 changed files with 149 additions and 133 deletions
+1 -2
View File
@@ -96,7 +96,6 @@ sql := sqlbuilder.CreateTable("users").
SQL(
sqlbuilder.Select("columns[0] id", "columns[1] name", "columns[2] year").
From("`all-users.csv`").
Limit(100).
String(),
).
String()
@@ -104,7 +103,7 @@ sql := sqlbuilder.CreateTable("users").
fmt.Println(sql)
// Output:
// CREATE TABLE users PARTITION BY (year) AS SELECT columns[0] id, columns[1] name, columns[2] year FROM `all-users.csv` LIMIT 100
// CREATE TABLE users PARTITION BY (year) AS SELECT columns[0] id, columns[1] name, columns[2] year FROM `all-users.csv`
```
Below are several utility methods designed to address special cases.
+9 -9
View File
@@ -3,10 +3,6 @@
package sqlbuilder
import (
"strconv"
)
const (
deleteMarkerInit injectionMarker = iota
deleteMarkerAfterWith
@@ -31,7 +27,6 @@ func newDeleteBuilder() *DeleteBuilder {
Cond: Cond{
Args: args,
},
limit: -1,
args: args,
injection: newInjection(),
}
@@ -51,7 +46,7 @@ type DeleteBuilder struct {
tables []string
orderByCols []string
order string
limit int
limitVar string
args *Args
@@ -152,7 +147,12 @@ func (db *DeleteBuilder) Desc() *DeleteBuilder {
// Limit sets the LIMIT in DELETE.
func (db *DeleteBuilder) Limit(limit int) *DeleteBuilder {
db.limit = limit
if limit < 0 {
db.limitVar = ""
return db
}
db.limitVar = db.Var(limit)
db.marker = deleteMarkerAfterLimit
return db
}
@@ -211,9 +211,9 @@ func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
db.injection.WriteTo(buf, deleteMarkerAfterOrderBy)
}
if db.limit >= 0 {
if len(db.limitVar) > 0 {
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(db.limit))
buf.WriteString(db.limitVar)
db.injection.WriteTo(buf, deleteMarkerAfterLimit)
}
+3 -3
View File
@@ -21,7 +21,7 @@ func ExampleDeleteFrom() {
fmt.Println(sql)
// Output:
// DELETE FROM demo.user WHERE status = 1 LIMIT 10
// DELETE FROM demo.user WHERE status = 1 LIMIT ?
}
func ExampleDeleteBuilder() {
@@ -65,8 +65,8 @@ func ExampleDeleteBuilder_SQL() {
fmt.Println(args)
// Output:
// /* before */ DELETE FROM demo.user PARTITION (p0) WHERE id > ? /* after where */ ORDER BY id /* after order by */ LIMIT 10 /* after limit */
// [1234]
// /* before */ DELETE FROM demo.user PARTITION (p0) WHERE id > ? /* after where */ ORDER BY id /* after order by */ LIMIT ? /* after limit */
// [1234 10]
}
func ExampleDeleteBuilder_With() {
+57 -42
View File
@@ -5,7 +5,6 @@ package sqlbuilder
import (
"fmt"
"strconv"
"strings"
)
@@ -51,8 +50,6 @@ func newSelectBuilder() *SelectBuilder {
Cond: Cond{
Args: args,
},
limit: -1,
offset: -1,
args: args,
injection: newInjection(),
}
@@ -79,8 +76,8 @@ type SelectBuilder struct {
groupByCols []string
orderByCols []string
order string
limit int
offset int
limitVar string
offsetVar string
forWhat string
args *Args
@@ -249,14 +246,24 @@ func (sb *SelectBuilder) Desc() *SelectBuilder {
// Limit sets the LIMIT in SELECT.
func (sb *SelectBuilder) Limit(limit int) *SelectBuilder {
sb.limit = limit
if limit < 0 {
sb.limitVar = ""
return sb
}
sb.limitVar = sb.Var(limit)
sb.marker = selectMarkerAfterLimit
return sb
}
// Offset sets the LIMIT offset in SELECT.
func (sb *SelectBuilder) Offset(offset int) *SelectBuilder {
sb.offset = offset
if offset < 0 {
sb.offsetVar = ""
return sb
}
sb.offsetVar = sb.Var(offset)
sb.marker = selectMarkerAfterLimit
return sb
}
@@ -314,7 +321,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
buf := newStringBuilder()
sb.injection.WriteTo(buf, selectMarkerInit)
oraclePage := flavor == Oracle && (sb.limit >= 0 || sb.offset >= 0)
oraclePage := flavor == Oracle && (len(sb.limitVar) > 0 || len(sb.offsetVar) > 0)
if sb.cteBuilderVar != "" {
buf.WriteLeadingString(sb.cteBuilderVar)
@@ -349,7 +356,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
if oraclePage {
if len(sb.selectCols) > 0 {
buf.WriteLeadingString("FROM ( SELECT ")
buf.WriteLeadingString("FROM (SELECT ")
if sb.distinct {
buf.WriteString("DISTINCT ")
@@ -368,7 +375,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
}
buf.WriteStrings(selectCols, ", ")
buf.WriteLeadingString("FROM ( SELECT ")
buf.WriteLeadingString("FROM (SELECT ")
buf.WriteStrings(sb.selectCols, ", ")
}
}
@@ -436,92 +443,100 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
switch flavor {
case MySQL, SQLite, ClickHouse:
if sb.limit >= 0 {
if len(sb.limitVar) > 0 {
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(sb.limit))
buf.WriteString(sb.limitVar)
if sb.offset >= 0 {
if len(sb.offsetVar) > 0 {
buf.WriteLeadingString("OFFSET ")
buf.WriteString(strconv.Itoa(sb.offset))
buf.WriteString(sb.offsetVar)
}
}
case CQL:
if sb.limit >= 0 {
if len(sb.limitVar) > 0 {
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(sb.limit))
buf.WriteString(sb.limitVar)
}
case PostgreSQL, Presto:
if sb.limit >= 0 {
if len(sb.limitVar) > 0 {
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(sb.limit))
buf.WriteString(sb.limitVar)
}
if sb.offset >= 0 {
if len(sb.offsetVar) > 0 {
buf.WriteLeadingString("OFFSET ")
buf.WriteString(strconv.Itoa(sb.offset))
buf.WriteString(sb.offsetVar)
}
case SQLServer:
// If ORDER BY is not set, sort column #1 by default.
// It's required to make OFFSET...FETCH work.
if len(sb.orderByCols) == 0 && (sb.limit >= 0 || sb.offset >= 0) {
if len(sb.orderByCols) == 0 && (len(sb.limitVar) > 0 || len(sb.offsetVar) > 0) {
buf.WriteLeadingString("ORDER BY 1")
}
if sb.offset >= 0 {
if len(sb.offsetVar) > 0 {
buf.WriteLeadingString("OFFSET ")
buf.WriteString(strconv.Itoa(sb.offset))
buf.WriteString(sb.offsetVar)
buf.WriteString(" ROWS")
}
if sb.limit >= 0 {
if sb.offset < 0 {
if len(sb.limitVar) > 0 {
if len(sb.offsetVar) == 0 {
buf.WriteLeadingString("OFFSET 0 ROWS")
}
buf.WriteLeadingString("FETCH NEXT ")
buf.WriteString(strconv.Itoa(sb.limit))
buf.WriteString(sb.limitVar)
buf.WriteString(" ROWS ONLY")
}
case Oracle:
if oraclePage {
buf.WriteString(" ) ")
buf.WriteString(") ")
if len(sb.tables) > 0 {
buf.WriteStrings(sb.tables, ", ")
}
min := sb.offset
if min < 0 {
min = 0
}
buf.WriteString(") WHERE ")
buf.WriteString(" ) WHERE ")
if sb.limit >= 0 {
if len(sb.limitVar) > 0 {
buf.WriteString("r BETWEEN ")
buf.WriteString(strconv.Itoa(min + 1))
buf.WriteString(" AND ")
buf.WriteString(strconv.Itoa(sb.limit + min))
if len(sb.offsetVar) > 0 {
buf.WriteString(sb.offsetVar)
buf.WriteString(" + 1 AND ")
buf.WriteString(sb.limitVar)
buf.WriteString(" + ")
buf.WriteString(sb.offsetVar)
} else {
buf.WriteString("1 AND ")
buf.WriteString(sb.limitVar)
buf.WriteString(" + 1")
}
} else {
// As oraclePage is true, sb.offsetVar must not be empty.
buf.WriteString("r >= ")
buf.WriteString(strconv.Itoa(min + 1))
buf.WriteString(sb.offsetVar)
buf.WriteString(" + 1")
}
}
case Informix:
// [SKIP N] FIRST M
// M must be greater than 0
if sb.limit > 0 {
if sb.offset >= 0 {
if len(sb.limitVar) > 0 {
if len(sb.offsetVar) > 0 {
buf.WriteLeadingString("SKIP ")
buf.WriteString(strconv.Itoa(sb.offset))
buf.WriteString(sb.offsetVar)
}
buf.WriteLeadingString("FIRST ")
buf.WriteString(strconv.Itoa(sb.limit))
buf.WriteString(sb.limitVar)
}
}
if sb.limit >= 0 {
if len(sb.limitVar) > 0 {
sb.injection.WriteTo(buf, selectMarkerAfterLimit)
}
+45 -49
View File
@@ -12,22 +12,18 @@ import (
)
func ExampleSelect() {
// Build a SQL to create a HIVE table.
s := CreateTable("users").
SQL("PARTITION BY (year)").
SQL("AS").
SQL(
Select("columns[0] id", "columns[1] name", "columns[2] year").
From("`all-users.csv`").
Limit(100).
String(),
).
String()
// Build a SQL to create a HIVE table using MySQL-like SQL syntax.
sql, args := Select("columns[0] id", "columns[1] name", "columns[2] year").
From(MySQL.Quote("all-users.csv")).
Limit(100).
Build()
fmt.Println(s)
fmt.Println(sql)
fmt.Println(args)
// Output:
// CREATE TABLE users PARTITION BY (year) AS SELECT columns[0] id, columns[1] name, columns[2] year FROM `all-users.csv` LIMIT 100
// SELECT columns[0] id, columns[1] name, columns[2] year FROM `all-users.csv` LIMIT ?
// [100]
}
func ExampleSelectBuilder() {
@@ -56,8 +52,8 @@ func ExampleSelectBuilder() {
fmt.Println(args)
// Output:
// SELECT DISTINCT id, name, COUNT(*) AS t FROM demo.user WHERE id > ? AND name LIKE ? AND (id_card IS NULL OR status IN (?, ?, ?)) AND id NOT IN (SELECT id FROM banned) AND modified_at > created_at + ? GROUP BY status HAVING status NOT IN (?, ?) ORDER BY modified_at ASC LIMIT 10 OFFSET 5
// [1234 %Du 1 2 5 86400 4 5]
// SELECT DISTINCT id, name, COUNT(*) AS t FROM demo.user WHERE id > ? AND name LIKE ? AND (id_card IS NULL OR status IN (?, ?, ?)) AND id NOT IN (SELECT id FROM banned) AND modified_at > created_at + ? GROUP BY status HAVING status NOT IN (?, ?) ORDER BY modified_at ASC LIMIT ? OFFSET ?
// [1234 %Du 1 2 5 86400 4 5 10 5]
}
func ExampleSelectBuilder_advancedUsage() {
@@ -191,65 +187,65 @@ func ExampleSelectBuilder_limit_offset() {
// MySQL
// #1: SELECT * FROM user
// #2: SELECT * FROM user
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
// #5: SELECT * FROM user ORDER BY id LIMIT 1 OFFSET 1
// #3: SELECT * FROM user LIMIT ? OFFSET ?
// #4: SELECT * FROM user LIMIT ?
// #5: SELECT * FROM user ORDER BY id LIMIT ? OFFSET ?
//
// PostgreSQL
// #1: SELECT * FROM user
// #2: SELECT * FROM user OFFSET 0
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
// #5: SELECT * FROM user ORDER BY id LIMIT 1 OFFSET 1
// #2: SELECT * FROM user OFFSET $1
// #3: SELECT * FROM user LIMIT $1 OFFSET $2
// #4: SELECT * FROM user LIMIT $1
// #5: SELECT * FROM user ORDER BY id LIMIT $1 OFFSET $2
//
// SQLite
// #1: SELECT * FROM user
// #2: SELECT * FROM user
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
// #5: SELECT * FROM user ORDER BY id LIMIT 1 OFFSET 1
// #3: SELECT * FROM user LIMIT ? OFFSET ?
// #4: SELECT * FROM user LIMIT ?
// #5: SELECT * FROM user ORDER BY id LIMIT ? OFFSET ?
//
// SQLServer
// #1: SELECT * FROM user
// #2: SELECT * FROM user ORDER BY 1 OFFSET 0 ROWS
// #3: SELECT * FROM user ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
// #4: SELECT * FROM user ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
// #5: SELECT * FROM user ORDER BY id OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
// #2: SELECT * FROM user ORDER BY 1 OFFSET @p1 ROWS
// #3: SELECT * FROM user ORDER BY 1 OFFSET @p1 ROWS FETCH NEXT @p2 ROWS ONLY
// #4: SELECT * FROM user ORDER BY 1 OFFSET 0 ROWS FETCH NEXT @p1 ROWS ONLY
// #5: SELECT * FROM user ORDER BY id OFFSET @p1 ROWS FETCH NEXT @p2 ROWS ONLY
//
// CQL
// #1: SELECT * FROM user
// #2: SELECT * FROM user
// #3: SELECT * FROM user LIMIT 1
// #4: SELECT * FROM user LIMIT 1
// #5: SELECT * FROM user ORDER BY id LIMIT 1
// #3: SELECT * FROM user LIMIT ?
// #4: SELECT * FROM user LIMIT ?
// #5: SELECT * FROM user ORDER BY id LIMIT ?
//
// ClickHouse
// #1: SELECT * FROM user
// #2: SELECT * FROM user
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
// #5: SELECT * FROM user ORDER BY id LIMIT 1 OFFSET 1
// #3: SELECT * FROM user LIMIT ? OFFSET ?
// #4: SELECT * FROM user LIMIT ?
// #5: SELECT * FROM user ORDER BY id LIMIT ? OFFSET ?
//
// Presto
// #1: SELECT * FROM user
// #2: SELECT * FROM user OFFSET 0
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
// #5: SELECT * FROM user ORDER BY id LIMIT 1 OFFSET 1
// #2: SELECT * FROM user OFFSET ?
// #3: SELECT * FROM user LIMIT ? OFFSET ?
// #4: SELECT * FROM user LIMIT ?
// #5: SELECT * FROM user ORDER BY id LIMIT ? OFFSET ?
//
// Oracle
// #1: SELECT * FROM user
// #2: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ) user ) WHERE r >= 1
// #3: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ) user ) WHERE r BETWEEN 1 AND 1
// #4: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ) user ) WHERE r BETWEEN 1 AND 1
// #5: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ORDER BY id ) user ) WHERE r BETWEEN 2 AND 2
// #2: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user) user) WHERE r >= :1 + 1
// #3: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user) user) WHERE r BETWEEN :1 + 1 AND :2 + :3
// #4: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user) user) WHERE r BETWEEN 1 AND :1 + 1
// #5: SELECT * FROM (SELECT ROWNUM r, * FROM (SELECT * FROM user ORDER BY id) user) WHERE r BETWEEN :1 + 1 AND :2 + :3
//
// Informix
// #1: SELECT * FROM user
// #2: SELECT * FROM user
// #3: SELECT * FROM user SKIP 0 FIRST 1
// #4: SELECT * FROM user FIRST 1
// #5: SELECT * FROM user ORDER BY id SKIP 1 FIRST 1
// #3: SELECT * FROM user SKIP ? FIRST ?
// #4: SELECT * FROM user FIRST ?
// #5: SELECT * FROM user ORDER BY id SKIP ? FIRST ?
}
func ExampleSelectBuilder_ForUpdate() {
@@ -314,7 +310,7 @@ func ExampleSelectBuilder_SQL() {
fmt.Println(s)
// Output:
// /* before */ SELECT u.id, u.name, c.type, p.nickname /* after select */ FROM user u /* after from */ JOIN contract c ON u.id = c.user_id RIGHT OUTER JOIN person p ON u.id = p.user_id /* after join */ WHERE u.modified_at > u.created_at /* after where */ ORDER BY id /* after order by */ LIMIT 10 /* after limit */ FOR SHARE /* after for */
// /* before */ SELECT u.id, u.name, c.type, p.nickname /* after select */ FROM user u /* after from */ JOIN contract c ON u.id = c.user_id RIGHT OUTER JOIN person p ON u.id = p.user_id /* after join */ WHERE u.modified_at > u.created_at /* after where */ ORDER BY id /* after order by */ LIMIT ? /* after limit */ FOR SHARE /* after for */
}
// Example for issue #115.
@@ -365,7 +361,7 @@ func ExampleSelectBuilder_With() {
fmt.Println(sql)
// Output:
// WITH users AS (SELECT id, name FROM users WHERE prime IS NOT NULL), orders AS (SELECT id, user_id FROM orders) SELECT orders.id FROM orders JOIN users ON orders.user_id = users.id LIMIT 10
// WITH users AS (SELECT id, name FROM users WHERE prime IS NOT NULL), orders AS (SELECT id, user_id FROM orders) SELECT orders.id FROM orders JOIN users ON orders.user_id = users.id LIMIT ?
}
func TestSelectBuilderSelectMore(t *testing.T) {
@@ -412,5 +408,5 @@ func ExampleSelectBuilder_LateralAs() {
fmt.Println(sb)
// Output:
// SELECT salesperson.name, max_sale.amount, max_sale.customer_name FROM salesperson, LATERAL (SELECT amount, customer_name FROM all_sales WHERE all_sales.salesperson_id = salesperson.id ORDER BY amount DESC LIMIT 1) AS max_sale
// SELECT salesperson.name, max_sale.amount, max_sale.customer_name FROM salesperson, LATERAL (SELECT amount, customer_name FROM all_sales WHERE all_sales.salesperson_id = salesperson.id ORDER BY amount DESC LIMIT ?) AS max_sale
}
+1 -1
View File
@@ -1036,6 +1036,6 @@ func ExampleFieldMapperFunc() {
fmt.Println(sql1 == sql2)
// Output:
// SELECT orders.id, orders.user_id, orders.product_name, orders.status, orders.user_addr_line1, orders.user_addr_line2, orders.created_at FROM orders LIMIT 10
// SELECT orders.id, orders.user_id, orders.product_name, orders.status, orders.user_addr_line1, orders.user_addr_line2, orders.created_at FROM orders LIMIT ?
// true
}
+20 -17
View File
@@ -3,10 +3,6 @@
package sqlbuilder
import (
"strconv"
)
const (
unionDistinct = " UNION " // Default union type is DISTINCT.
unionAll = " UNION ALL "
@@ -26,9 +22,6 @@ func NewUnionBuilder() *UnionBuilder {
func newUnionBuilder() *UnionBuilder {
return &UnionBuilder{
limit: -1,
offset: -1,
args: &Args{},
injection: newInjection(),
}
@@ -40,8 +33,8 @@ type UnionBuilder struct {
builderVars []string
orderByCols []string
order string
limit int
offset int
limitVar string
offsetVar string
args *Args
@@ -107,14 +100,24 @@ func (ub *UnionBuilder) Desc() *UnionBuilder {
// Limit sets the LIMIT in SELECT.
func (ub *UnionBuilder) Limit(limit int) *UnionBuilder {
ub.limit = limit
if limit < 0 {
ub.limitVar = ""
return ub
}
ub.limitVar = ub.Var(limit)
ub.marker = unionMarkerAfterLimit
return ub
}
// Offset sets the LIMIT offset in SELECT.
func (ub *UnionBuilder) Offset(offset int) *UnionBuilder {
ub.offset = offset
if offset < 0 {
ub.offsetVar = ""
return ub
}
ub.offsetVar = ub.Var(offset)
ub.marker = unionMarkerAfterLimit
return ub
}
@@ -177,20 +180,20 @@ func (ub *UnionBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}
ub.injection.WriteTo(buf, unionMarkerAfterOrderBy)
}
if ub.limit >= 0 {
if len(ub.limitVar) > 0 {
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(ub.limit))
buf.WriteString(ub.limitVar)
}
if ((MySQL == flavor || Informix == flavor) && ub.limit >= 0) || PostgreSQL == flavor {
if ub.offset >= 0 {
if ((MySQL == flavor || Informix == flavor) && len(ub.limitVar) > 0) || PostgreSQL == flavor {
if len(ub.offsetVar) > 0 {
buf.WriteLeadingString("OFFSET ")
buf.WriteString(strconv.Itoa(ub.offset))
buf.WriteString(ub.offsetVar)
}
}
if ub.limit >= 0 {
if len(ub.limitVar) > 0 {
ub.injection.WriteTo(buf, unionMarkerAfterLimit)
}
+3 -3
View File
@@ -54,8 +54,8 @@ func ExampleUnionAll() {
fmt.Println(args)
// Output:
// (SELECT id, name, created_at FROM demo.user WHERE id > ?) UNION ALL (TABLE demo.user_profile) ORDER BY created_at ASC LIMIT 100 OFFSET 5
// [1234]
// (SELECT id, name, created_at FROM demo.user WHERE id > ?) UNION ALL (TABLE demo.user_profile) ORDER BY created_at ASC LIMIT ? OFFSET ?
// [1234 100 5]
}
func ExampleUnionBuilder_SQL() {
@@ -80,7 +80,7 @@ func ExampleUnionBuilder_SQL() {
fmt.Println(sql)
// Output:
// /* before */ (SELECT id, name, created_at FROM demo.user) UNION (SELECT id, avatar FROM demo.user_profile) /* after union */ ORDER BY created_at DESC /* after order by */ LIMIT 100 OFFSET 5 /* after limit */
// /* before */ (SELECT id, name, created_at FROM demo.user) UNION (SELECT id, avatar FROM demo.user_profile) /* after union */ ORDER BY created_at DESC /* after order by */ LIMIT ? OFFSET ? /* after limit */
}
func TestUnionForSQLite(t *testing.T) {
+9 -6
View File
@@ -5,7 +5,6 @@ package sqlbuilder
import (
"fmt"
"strconv"
)
const (
@@ -33,7 +32,6 @@ func newUpdateBuilder() *UpdateBuilder {
Cond: Cond{
Args: args,
},
limit: -1,
args: args,
injection: newInjection(),
}
@@ -54,7 +52,7 @@ type UpdateBuilder struct {
assignments []string
orderByCols []string
order string
limit int
limitVar string
args *Args
@@ -208,7 +206,12 @@ func (ub *UpdateBuilder) Desc() *UpdateBuilder {
// Limit sets the LIMIT in UPDATE.
func (ub *UpdateBuilder) Limit(limit int) *UpdateBuilder {
ub.limit = limit
if limit < 0 {
ub.limitVar = ""
return ub
}
ub.limitVar = ub.Var(limit)
ub.marker = updateMarkerAfterLimit
return ub
}
@@ -300,9 +303,9 @@ func (ub *UpdateBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
ub.injection.WriteTo(buf, updateMarkerAfterOrderBy)
}
if ub.limit >= 0 {
if len(ub.limitVar) > 0 {
buf.WriteLeadingString("LIMIT ")
buf.WriteString(strconv.Itoa(ub.limit))
buf.WriteString(ub.limitVar)
ub.injection.WriteTo(buf, updateMarkerAfterLimit)
}
+1 -1
View File
@@ -114,7 +114,7 @@ func ExampleUpdateBuilder_SQL() {
fmt.Println(sql)
// Output:
// /* before */ UPDATE demo.user /* after update */ SET type = ? /* after set */ ORDER BY id DESC /* after order by */ LIMIT 10 /* after limit */
// /* before */ UPDATE demo.user /* after update */ SET type = ? /* after set */ ORDER BY id DESC /* after order by */ LIMIT ? /* after limit */
}
func ExampleUpdateBuilder_NumAssignment() {