Skip to content

Commit 4c423e8

Browse files
aquaomriido50
authored andcommitted
Add support to Set command.
The SET command changes run-time configuration parameters of PostgreSQL. This commit adds support to the SET command. User may also run the SET command with the LOCAL or SESSION annotation options to control the lifespan of the coniguration. One common use case of the Set command is to set statement timeout; For that reason: a convenient method 'SetTimeout' was added to the transaction struct.
1 parent 9f2e2c0 commit 4c423e8

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

set.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package sqlz
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/jmoiron/sqlx"
10+
)
11+
12+
// SetCmd represents a PostgreSQL SET command
13+
type SetCmd struct {
14+
*Statement
15+
level string
16+
configParam string
17+
value string
18+
execer Ext
19+
}
20+
21+
// Set creates a new SetCmd object, with configuration parameter
22+
// and its value.
23+
func (db *DB) Set(configParam, value string) *SetCmd {
24+
return &SetCmd{
25+
configParam: configParam,
26+
value: value,
27+
execer: db.DB,
28+
Statement: &Statement{db.ErrHandlers},
29+
}
30+
}
31+
32+
// Set creates a new SetCmd object, with configuration parameter
33+
// and its value.
34+
func (tx *Tx) Set(configParam, value string) *SetCmd {
35+
return &SetCmd{
36+
configParam: configParam,
37+
value: value,
38+
execer: tx.Tx,
39+
Statement: &Statement{tx.ErrHandlers},
40+
}
41+
}
42+
43+
// SetTimeout sets a statement timeout. When set, any statement
44+
// (in the transaction) that takes more than the specified duration
45+
// will be aborted, starting from the time the command arrives
46+
// at the server from the client. A value of zero turns this off.
47+
func (tx *Tx) SetTimeout(d time.Duration) (res sql.Result, err error) {
48+
stmt := &SetCmd{
49+
configParam: "statement_timeout",
50+
value: fmt.Sprintf("\"%dms\"", d.Milliseconds()),
51+
execer: tx.Tx,
52+
Statement: &Statement{tx.ErrHandlers},
53+
}
54+
55+
return stmt.Local().Exec()
56+
}
57+
58+
// Local sets the configuration parameter locally in a transaction.
59+
// The effect of SET LOCAL will last only till the end of the
60+
// current transaction, whether committed or not.
61+
func (cmd *SetCmd) Local() *SetCmd {
62+
cmd.level = "LOCAL"
63+
return cmd
64+
}
65+
66+
// Session sets the configuration parameter to the entire session.
67+
// The effect of SET SESSION will last only till the end of the
68+
// current session. if issued within a transaction that is later aborted,
69+
// the effects of the SET command disappear when the transaction is rolled
70+
// back. Once the surrounding transaction is committed, the effects will persist
71+
// until the end of the session, unless overridden by another SET.
72+
func (cmd *SetCmd) Session() *SetCmd {
73+
cmd.level = "SESSION"
74+
return cmd
75+
}
76+
77+
// ToSQL generates the SET command SQL and returns a list of
78+
// bindings. It is used internally by Exec, but is exported if you
79+
// wish to use it directly.
80+
func (cmd *SetCmd) ToSQL(rebind bool) (string, []interface{}) {
81+
clauses := []string{"SET"}
82+
if cmd.level != "" {
83+
clauses = append(clauses, cmd.level)
84+
}
85+
86+
clauses = append(clauses, cmd.configParam, "TO", cmd.value)
87+
88+
asSQL := strings.Join(clauses, " ")
89+
90+
if rebind {
91+
if db, ok := cmd.execer.(*sqlx.DB); ok {
92+
asSQL = db.Rebind(asSQL)
93+
} else if tx, ok := cmd.execer.(*sqlx.Tx); ok {
94+
asSQL = tx.Rebind(asSQL)
95+
}
96+
}
97+
98+
return asSQL, []interface{}{}
99+
}
100+
101+
// Exec executes the SET command, returning the standard
102+
// sql.Result struct and an error if the query failed.
103+
func (cmd *SetCmd) Exec() (res sql.Result, err error) {
104+
asSQL, bindings := cmd.ToSQL(true)
105+
res, err = cmd.execer.Exec(asSQL, bindings...)
106+
cmd.Statement.HandleError(err)
107+
108+
return res, err
109+
}

set_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package sqlz
2+
3+
import "testing"
4+
5+
func TestSet(t *testing.T) {
6+
runTests(t, func(dbz *DB) []test {
7+
return []test{
8+
{
9+
name: "simple set",
10+
stmt: dbz.Set("key", "value"),
11+
expectedSQL: "SET key TO value",
12+
},
13+
{
14+
name: "local set",
15+
stmt: dbz.Set("key", "value").Local(),
16+
expectedSQL: "SET LOCAL key TO value",
17+
},
18+
{
19+
name: "session set",
20+
stmt: dbz.Set("key", "value").Session(),
21+
expectedSQL: "SET SESSION key TO value",
22+
},
23+
}
24+
})
25+
}

0 commit comments

Comments
 (0)