Fix moderncsqlite errors and rebase onto main (#2832)

This is #2819 but rebased on latest `main`. This PR is against main too
as opposed to the `moderncsqlite` branch.

The main change here is simply:

```go
// add query parameters to the dsn
if strings.Contains(dsn, "?") {
	dsn += "&"
} else {
	dsn += "?"
}

// wait some time before erroring if the db is locked
// https://gitlab.com/cznic/sqlite/-/issues/106#note_1058094993
dsn += "_pragma=busy_timeout%3d10000"
```

### Pull Request Checklist

<!-- Please read
https://matrix-org.github.io/dendrite/development/contributing before
submitting your pull request -->

* [x] I have added tests for PR _or_ I have justified why this PR
doesn't need tests.
* [x] Pull request includes a [sign off below using a legally
identifiable
name](https://matrix-org.github.io/dendrite/development/contributing#sign-off)
_or_ I have already signed off privately

Signed off privately.

Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com>
This commit is contained in:
0x1a8510f2 2022-11-02 13:20:10 +00:00 committed by GitHub
parent 16c2a95900
commit 51ab0a8ccf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 193 additions and 62 deletions

View file

@ -7,8 +7,6 @@ import (
"reflect"
"testing"
_ "github.com/mattn/go-sqlite3"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/test"
)
@ -88,7 +86,7 @@ func Test_migrations_Up(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
driverName := "sqlite3"
driverName := sqlutil.SQLITE_DRIVER_NAME
if dbType == test.DBTypePostgres {
driverName = "postgres"
}
@ -117,7 +115,7 @@ func Test_insertMigration(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
conStr, close := test.PrepareDBConnectionString(t, dbType)
defer close()
driverName := "sqlite3"
driverName := sqlutil.SQLITE_DRIVER_NAME
if dbType == test.DBTypePostgres {
driverName = "postgres"
}

View file

@ -0,0 +1,19 @@
//go:build cgo
// +build cgo
package sqlutil
import (
"github.com/mattn/go-sqlite3"
_ "github.com/mattn/go-sqlite3"
)
const SQLITE_DRIVER_NAME = "sqlite3"
func sqliteDSNExtension(dsn string) string {
return dsn
}
func sqliteDriver() *sqlite3.SQLiteDriver {
return &sqlite3.SQLiteDriver{}
}

View file

@ -0,0 +1,29 @@
//go:build !cgo
// +build !cgo
package sqlutil
import (
"modernc.org/sqlite"
"strings"
)
const SQLITE_DRIVER_NAME = "sqlite"
func sqliteDSNExtension(dsn string) string {
// add query parameters to the dsn
if strings.Contains(dsn, "?") {
dsn += "&"
} else {
dsn += "?"
}
// wait some time before erroring if the db is locked
// https://gitlab.com/cznic/sqlite/-/issues/106#note_1058094993
dsn += "_pragma=busy_timeout%3d10000"
return dsn
}
func sqliteDriver() *sqlite.Driver {
return &sqlite.Driver{}
}

View file

@ -20,11 +20,12 @@ func Open(dbProperties *config.DatabaseOptions, writer Writer) (*sql.DB, error)
var driverName, dsn string
switch {
case dbProperties.ConnectionString.IsSQLite():
driverName = "sqlite3"
driverName = SQLITE_DRIVER_NAME
dsn, err = ParseFileURI(dbProperties.ConnectionString)
if err != nil {
return nil, fmt.Errorf("ParseFileURI: %w", err)
}
dsn = sqliteDSNExtension(dsn)
case dbProperties.ConnectionString.IsPostgres():
driverName = "postgres"
dsn = string(dbProperties.ConnectionString)
@ -39,7 +40,7 @@ func Open(dbProperties *config.DatabaseOptions, writer Writer) (*sql.DB, error)
if err != nil {
return nil, err
}
if driverName != "sqlite3" {
if driverName != SQLITE_DRIVER_NAME {
logger := logrus.WithFields(logrus.Fields{
"max_open_conns": dbProperties.MaxOpenConns(),
"max_idle_conns": dbProperties.MaxIdleConns(),

View file

@ -21,7 +21,6 @@ import (
"database/sql"
"github.com/lib/pq"
sqlite "github.com/mattn/go-sqlite3"
"github.com/ngrok/sqlmw"
)
@ -31,6 +30,6 @@ func registerDrivers() {
}
// install the wrapped drivers
sql.Register("postgres-trace", sqlmw.Driver(&pq.Driver{}, new(traceInterceptor)))
sql.Register("sqlite3-trace", sqlmw.Driver(&sqlite.SQLiteDriver{}, new(traceInterceptor)))
sql.Register("sqlite3-trace", sqlmw.Driver(sqliteDriver(), new(traceInterceptor)))
}

View file

@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !wasm
// +build !wasm
//go:build !wasm && !cgo
// +build !wasm,!cgo
package sqlutil
import (
"github.com/lib/pq"
"github.com/mattn/go-sqlite3"
"modernc.org/sqlite"
lib "modernc.org/sqlite/lib"
)
// IsUniqueConstraintViolationErr returns true if the error is an unique_violation error
@ -27,10 +28,8 @@ func IsUniqueConstraintViolationErr(err error) bool {
switch e := err.(type) {
case *pq.Error:
return e.Code == "23505"
case *sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case *sqlite.Error:
return e.Code() == lib.SQLITE_CONSTRAINT
}
return false
}

View file

@ -0,0 +1,36 @@
// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !wasm && cgo
// +build !wasm,cgo
package sqlutil
import (
"github.com/lib/pq"
"github.com/mattn/go-sqlite3"
)
// IsUniqueConstraintViolationErr returns true if the error is an unique_violation error
func IsUniqueConstraintViolationErr(err error) bool {
switch e := err.(type) {
case *pq.Error:
return e.Code == "23505"
case *sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
}
return false
}

View file

@ -17,15 +17,16 @@
package sqlutil
import "github.com/mattn/go-sqlite3"
import (
"modernc.org/sqlite"
lib "modernc.org/sqlite/lib"
)
// IsUniqueConstraintViolationErr returns true if the error is an unique_violation error
func IsUniqueConstraintViolationErr(err error) bool {
switch e := err.(type) {
case *sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case sqlite3.Error:
return e.Code == sqlite3.ErrConstraint
case *sqlite.Error:
return e.Code() == lib.SQLITE_CONSTRAINT
}
return false
}