Skip to content

Commit e8edcb1

Browse files
committed
feat: Add multistmt support to firebird driver
1 parent 2788339 commit e8edcb1

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

database/firebird/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
| URL Query | WithInstance Config | Description |
66
|------------|---------------------|-------------|
77
| `x-migrations-table` | `MigrationsTable` | Name of the migrations table |
8+
| `x-multi-statement` | `MultiStatementEnabled` | Enable multi-statement execution (default: false) |
9+
| `x-multi-statement-max-size` | `MultiStatementMaxSize` | Maximum size of single statement in bytes (default: 10MB) |
810
| `auth_plugin_name` | | Authentication plugin name. Srp256/Srp/Legacy_Auth are available. (default is Srp) |
911
| `column_name_to_lower` | | Force column name to lower. (default is false) |
1012
| `role` | | Role name |
1113
| `tzname` | | Time Zone name. (For Firebird 4.0+) |
12-
| `wire_crypt` | | Enable wire data encryption or not. For Firebird 3.0+ (default is true) |
14+
| `wire_crypt` | | Enable wire data encryption or not. For Firebird 3.0+ (default is true) |

database/firebird/firebird.go

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import (
88
"fmt"
99
"io"
1010
nurl "net/url"
11+
"strconv"
12+
"strings"
1113

1214
"github.com/golang-migrate/migrate/v4"
1315
"github.com/golang-migrate/migrate/v4/database"
16+
"github.com/golang-migrate/migrate/v4/database/multistmt"
1417
"github.com/hashicorp/go-multierror"
1518
_ "github.com/nakagami/firebirdsql"
1619
"go.uber.org/atomic"
@@ -22,15 +25,22 @@ func init() {
2225
database.Register("firebirdsql", &db)
2326
}
2427

25-
var DefaultMigrationsTable = "schema_migrations"
28+
var (
29+
multiStmtDelimiter = []byte(";")
30+
31+
DefaultMigrationsTable = "schema_migrations"
32+
DefaultMultiStatementMaxSize = 10 * 1 << 20 // 10 MB
33+
)
2634

2735
var (
2836
ErrNilConfig = fmt.Errorf("no config")
2937
)
3038

3139
type Config struct {
32-
DatabaseName string
33-
MigrationsTable string
40+
DatabaseName string
41+
MigrationsTable string
42+
MultiStatementEnabled bool
43+
MultiStatementMaxSize int
3444
}
3545

3646
type Firebird struct {
@@ -85,9 +95,30 @@ func (f *Firebird) Open(dsn string) (database.Driver, error) {
8595
return nil, err
8696
}
8797

98+
multiStatementMaxSize := DefaultMultiStatementMaxSize
99+
if s := purl.Query().Get("x-multi-statement-max-size"); len(s) > 0 {
100+
multiStatementMaxSize, err = strconv.Atoi(s)
101+
if err != nil {
102+
return nil, err
103+
}
104+
if multiStatementMaxSize <= 0 {
105+
multiStatementMaxSize = DefaultMultiStatementMaxSize
106+
}
107+
}
108+
109+
multiStatementEnabled := false
110+
if s := purl.Query().Get("x-multi-statement"); len(s) > 0 {
111+
multiStatementEnabled, err = strconv.ParseBool(s)
112+
if err != nil {
113+
return nil, fmt.Errorf("unable to parse option x-multi-statement: %w", err)
114+
}
115+
}
116+
88117
px, err := WithInstance(db, &Config{
89-
MigrationsTable: purl.Query().Get("x-migrations-table"),
90-
DatabaseName: purl.Path,
118+
MigrationsTable: purl.Query().Get("x-migrations-table"),
119+
DatabaseName: purl.Path,
120+
MultiStatementEnabled: multiStatementEnabled,
121+
MultiStatementMaxSize: multiStatementMaxSize,
91122
})
92123

93124
if err != nil {
@@ -121,6 +152,26 @@ func (f *Firebird) Unlock() error {
121152
}
122153

123154
func (f *Firebird) Run(migration io.Reader) error {
155+
if f.config.MultiStatementEnabled {
156+
var err error
157+
158+
if e := multistmt.Parse(migration, multiStmtDelimiter, f.config.MultiStatementMaxSize, func(m []byte) bool {
159+
query := strings.TrimSpace(string(m))
160+
if len(query) == 0 {
161+
return true
162+
}
163+
if _, err = f.conn.ExecContext(context.Background(), query); err != nil {
164+
return false // stop parsing on error
165+
}
166+
return true // continue parsing
167+
}); e != nil {
168+
return &database.Error{OrigErr: e, Err: "error parsing multi-statement migration"}
169+
}
170+
if err != nil {
171+
return &database.Error{OrigErr: err, Err: "error executing multi-statement migration"}
172+
}
173+
return nil
174+
}
124175
migr, err := io.ReadAll(migration)
125176
if err != nil {
126177
return err

0 commit comments

Comments
 (0)