Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f90c751b10 | ||
|
|
c7a0a74aef | ||
|
|
50117bac35 | ||
|
|
d9c67dc417 | ||
|
|
a5075e2de1 | ||
|
|
9477979a55 | ||
|
|
f4abb4bba7 | ||
|
|
3461b6bfd7 | ||
|
|
602c5edb72 | ||
|
|
a7da767fa3 | ||
|
|
b55e3ea06d | ||
|
|
2bd822b3aa | ||
|
|
460d57267a | ||
|
|
1e4b96537d | ||
|
|
837dda3cc9 | ||
|
|
1620c56290 | ||
|
|
257fa847d6 | ||
|
|
001b70ac7d | ||
|
|
89e308c340 | ||
|
|
fed8fe9f0a | ||
|
|
472ef2e75c | ||
|
|
8d7625987a | ||
|
|
9f9df7c897 | ||
|
|
a371c8ea2b | ||
|
|
43cc3b3ea5 | ||
|
|
f939a89925 | ||
|
|
6dd86e0ded | ||
|
|
70e6d6d574 | ||
|
|
a51d0da644 | ||
|
|
3f583f0b61 | ||
|
|
ce3cb727b6 | ||
|
|
1ee8337800 | ||
|
|
952d08e30b | ||
|
|
39ab04d659 | ||
|
|
8b9c5f7712 | ||
|
|
b4ec9bccb1 | ||
|
|
ed4bdd4614 | ||
|
|
8945e853c4 | ||
|
|
7108d806dd | ||
|
|
682016f04c | ||
|
|
f3e6b5a737 | ||
|
|
0a17402aa2 | ||
|
|
5eee0c8030 | ||
|
|
30690d7df3 | ||
|
|
642a24d61b | ||
|
|
5300864bba | ||
|
|
278833935c | ||
|
|
6b9f24bf7f | ||
|
|
9023d66a0b | ||
|
|
10494908af | ||
|
|
033835ac1b | ||
|
|
329152ed62 | ||
|
|
34c2b4ad9c | ||
|
|
a3b7633246 | ||
|
|
5b97c921ed | ||
|
|
3c3ce91f29 | ||
|
|
f37ef795db | ||
|
|
1af841d787 | ||
|
|
7269490309 | ||
|
|
fccd197e40 | ||
|
|
e6d84f6f80 | ||
|
|
146bfa05b3 | ||
|
|
604248c97e | ||
|
|
a4d0a1b8d9 | ||
|
|
60d73be14e | ||
|
|
36d17ba2ec | ||
|
|
24a6476044 | ||
|
|
a8680333c3 | ||
|
|
8b091919d4 | ||
|
|
c5137c417c |
@@ -25,7 +25,7 @@ e.g. s3, github, go-bindata, gcs, file
|
||||
Obtained by running: `migrate -help`
|
||||
|
||||
**Loaded Database Drivers**
|
||||
e.g. spanner, stub, clickhouse, cockroachdb, crdb-postgres, postgres, postgresql, pgx, redshift, cassandra, cockroach, mysql
|
||||
e.g. spanner, stub, datastore, cockroachdb, crdb-postgres, postgres, postgresql, pgx, redshift, cassandra, cockroach, mysql
|
||||
Obtained by running: `migrate -help`
|
||||
|
||||
**Go Version**
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="640" viewBox="0 0 1280 640" role="img" aria-label="migrate">
|
||||
<rect width="1280" height="640" fill="#0A0A0A"/>
|
||||
<svg x="96" y="215" width="210" height="210" viewBox="0 0 67 67"><path d="M22.21 67V44.6369H0V67H22.21Z" fill="#fff"/><path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="#fff"/><path d="M22.21 0H0V22.3184H22.21V0Z" fill="#fff"/><path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#fff"/><path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#fff"/></svg>
|
||||
<text x="378" y="276" font-family="Inter,system-ui,-apple-system,sans-serif" font-size="78" font-weight="800" letter-spacing="-2" fill="#ffffff">migrate</text>
|
||||
<text x="378" y="322" font-family="Inter,system-ui,sans-serif" font-size="30" fill="#ffffff" opacity=".66">Database migrations. CLI and Golang library.</text>
|
||||
<rect x="378" y="338" width="806" height="3" rx="1.5" fill="#ffffff" opacity=".9"/>
|
||||
<text x="378" y="390" font-family="Inter,system-ui,sans-serif" font-size="24" font-weight="600" fill="#ffffff" opacity=".5">github.com/hanzoai</text>
|
||||
<text x="1184" y="390" text-anchor="end" font-family="Inter,system-ui,sans-serif" font-size="24" font-weight="600" fill="#ffffff" opacity=".5">hanzo.ai</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -7,22 +7,22 @@ on:
|
||||
jobs:
|
||||
lint:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.23.x"
|
||||
go-version: "1.26.4.x"
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: v1.63.4
|
||||
version: v2.6.2
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
strategy:
|
||||
matrix:
|
||||
go: ["1.22.x", "1.23.x"]
|
||||
go: ["1.24.x", "1.25.x"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
check-coverage:
|
||||
name: Check coverage
|
||||
needs: [test]
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
steps:
|
||||
- uses: shogo82148/actions-goveralls@v1
|
||||
with:
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
goreleaser:
|
||||
name: Release a new version
|
||||
needs: [lint, test]
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
environment: GoReleaser
|
||||
# This job only runs when
|
||||
# 1. When the previous `lint` and `test` jobs has completed successfully
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
ruby-version: 2.7
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.23.x"
|
||||
go-version: "1.26.4.x"
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.26.4'
|
||||
|
||||
- name: Build CLI binaries
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
mkdir -p cli/build
|
||||
|
||||
for pair in "linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64"; do
|
||||
OS=${pair%/*}
|
||||
ARCH=${pair#*/}
|
||||
OUTPUT="cli/build/migrate.${OS}-${ARCH}"
|
||||
echo "Building $OUTPUT..."
|
||||
CGO_ENABLED=0 GOOS=$OS GOARCH=$ARCH \
|
||||
go build -a -o "$OUTPUT" \
|
||||
-ldflags="-s -w -X main.Version=$VERSION" \
|
||||
-tags 'datastore file' \
|
||||
./cmd/migrate
|
||||
ln -f "$OUTPUT" cli/build/migrate
|
||||
tar czf "${OUTPUT}.tar.gz" -C cli/build migrate
|
||||
done
|
||||
|
||||
cd cli/build && sha256sum *.tar.gz > sha256sum.txt
|
||||
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release create ${{ github.ref_name }} \
|
||||
cli/build/*.tar.gz \
|
||||
cli/build/sha256sum.txt \
|
||||
--title "${{ github.ref_name }}" \
|
||||
--generate-notes \
|
||||
--latest
|
||||
@@ -8,3 +8,4 @@ vendor/
|
||||
.vscode/
|
||||
.idea
|
||||
dist/
|
||||
migrate
|
||||
|
||||
+29
-18
@@ -1,26 +1,37 @@
|
||||
run:
|
||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||
timeout: 5m
|
||||
version: "2"
|
||||
linters:
|
||||
enable:
|
||||
#- golint
|
||||
#- interfacer
|
||||
- unconvert
|
||||
#- dupl
|
||||
- goconst
|
||||
- gofmt
|
||||
- misspell
|
||||
- unparam
|
||||
- nakedret
|
||||
- prealloc
|
||||
#- gosec
|
||||
linters-settings:
|
||||
misspell:
|
||||
locale: US
|
||||
- revive
|
||||
- unconvert
|
||||
- unparam
|
||||
settings:
|
||||
misspell:
|
||||
locale: US
|
||||
revive:
|
||||
rules:
|
||||
- name: redundant-build-tag
|
||||
exclusions:
|
||||
generated: lax
|
||||
rules:
|
||||
- path: (.+)\.go$
|
||||
text: G104
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
issues:
|
||||
max-same-issues: 0
|
||||
max-issues-per-linter: 0
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
# gosec: Duplicated errcheck checks
|
||||
- G104
|
||||
max-same-issues: 0
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.23-alpine3.20 AS builder
|
||||
FROM golang:1.26.4-alpine3.21 AS builder
|
||||
ARG VERSION
|
||||
|
||||
RUN apk add --no-cache git gcc musl-dev make
|
||||
@@ -15,7 +15,7 @@ COPY . ./
|
||||
|
||||
RUN make build-docker
|
||||
|
||||
FROM alpine:3.20
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
and then "force" the expected version.
|
||||
|
||||
#### What happens if two programs try and update the database at the same time?
|
||||
Database-specific locking features are used by *some* database drivers to prevent multiple instances of migrate from running migrations at the same time
|
||||
Database-specific locking features are used by *some* database drivers to prevent multiple instances of migrate from running migrations on
|
||||
the same database at the same time. For example, the MySQL driver uses the `GET_LOCK` function, while the Postgres driver uses
|
||||
the `pg_advisory_lock` function.
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Hanzo Golang Migrate
|
||||
|
||||
## Overview
|
||||
Go module: github.com/golang-migrate/migrate/v4
|
||||
|
||||
## Tech Stack
|
||||
- **Language**: Go
|
||||
|
||||
## Build & Run
|
||||
```bash
|
||||
go build ./...
|
||||
go test ./...
|
||||
```
|
||||
|
||||
## Structure
|
||||
```
|
||||
golang-migrate/
|
||||
CONTRIBUTING.md
|
||||
Dockerfile
|
||||
Dockerfile.circleci
|
||||
Dockerfile.github-actions
|
||||
FAQ.md
|
||||
GETTING_STARTED.md
|
||||
LICENSE
|
||||
MIGRATIONS.md
|
||||
Makefile
|
||||
README.md
|
||||
SECURITY.md
|
||||
cli/
|
||||
cmd/
|
||||
database/
|
||||
dktesting/
|
||||
```
|
||||
|
||||
## Key Files
|
||||
- `README.md` -- Project documentation
|
||||
- `go.mod` -- Go module definition
|
||||
- `Makefile` -- Build automation
|
||||
- `Dockerfile` -- Container build
|
||||
@@ -1,5 +1,5 @@
|
||||
SOURCE ?= file go_bindata github github_ee bitbucket aws_s3 google_cloud_storage godoc_vfs gitlab
|
||||
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb yugabytedb clickhouse mongodb sqlserver firebird neo4j pgx pgx5 rqlite
|
||||
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb yugabytedb datastore mongodb sqlserver firebird neo4j pgx pgx5 rqlite
|
||||
DATABASE_TEST ?= $(DATABASE) sqlite sqlite3 sqlcipher
|
||||
VERSION ?= $(shell git describe --tags 2>/dev/null | cut -c 2-)
|
||||
TEST_FLAGS ?=
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<p align="center"><img src=".github/hero.svg" alt="migrate" width="880"></p>
|
||||
|
||||
[](https://github.com/golang-migrate/migrate/actions/workflows/ci.yaml?query=branch%3Amaster)
|
||||
[](https://pkg.go.dev/github.com/golang-migrate/migrate/v4)
|
||||
[](https://coveralls.io/github/golang-migrate/migrate?branch=master)
|
||||
[](https://packagecloud.io/golang-migrate/migrate?filter=debs)
|
||||
[](https://hub.docker.com/r/migrate/migrate/)
|
||||

|
||||

|
||||
[](https://github.com/golang-migrate/migrate/releases)
|
||||
[](https://goreportcard.com/report/github.com/golang-migrate/migrate/v4)
|
||||
|
||||
@@ -40,7 +42,7 @@ Database drivers run migrations. [Add a new database?](database/driver.go)
|
||||
* [Google Cloud Spanner](database/spanner)
|
||||
* [CockroachDB](database/cockroachdb)
|
||||
* [YugabyteDB](database/yugabytedb)
|
||||
* [ClickHouse](database/clickhouse)
|
||||
* [Datastore](database/datastore)
|
||||
* [Firebird](database/firebird)
|
||||
* [MS SQL Server](database/sqlserver)
|
||||
* [rqlite](database/rqlite)
|
||||
@@ -87,7 +89,7 @@ Source drivers read migrations from local or remote sources. [Add a new source?]
|
||||
* Handles ctrl+c (SIGINT) gracefully.
|
||||
* No config search paths, no config files, no magic ENV var injections.
|
||||
|
||||
__[CLI Documentation](cmd/migrate)__
|
||||
[CLI Documentation](cmd/migrate) (includes CLI install instructions)
|
||||
|
||||
### Basic usage
|
||||
|
||||
|
||||
+12
-8
@@ -27,8 +27,8 @@ $ scoop install migrate
|
||||
### Linux (*.deb package)
|
||||
|
||||
```bash
|
||||
$ curl -L https://packagecloud.io/golang-migrate/migrate/gpgkey | apt-key add -
|
||||
$ echo "deb https://packagecloud.io/golang-migrate/migrate/ubuntu/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/migrate.list
|
||||
$ curl -fsSL https://packagecloud.io/golang-migrate/migrate/gpgkey | sudo gpg --dearmor -o /etc/apt/keyrings/migrate.gpg
|
||||
$ echo "deb [signed-by=/etc/apt/keyrings/migrate.gpg] https://packagecloud.io/golang-migrate/migrate/ubuntu/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/migrate.list
|
||||
$ apt-get update
|
||||
$ apt-get install -y migrate
|
||||
```
|
||||
@@ -86,14 +86,18 @@ Options:
|
||||
-help Print usage
|
||||
|
||||
Commands:
|
||||
create [-ext E] [-dir D] [-seq] [-digits N] [-format] NAME
|
||||
Create a set of timestamped up/down migrations titled NAME, in directory D with extension E.
|
||||
Use -seq option to generate sequential up/down migrations with N digits.
|
||||
Use -format option to specify a Go time format string.
|
||||
create [-ext E] [-dir D] [-seq] [-digits N] [-format] [-tz] NAME
|
||||
Create a set of timestamped up/down migrations titled NAME, in directory D with extension E.
|
||||
Use -seq option to generate sequential up/down migrations with N digits.
|
||||
Use -format option to specify a Go time format string. Note: migrations with the same time cause "duplicate migration version" error.
|
||||
Use -tz option to specify the timezone that will be used when generating non-sequential migrations (defaults: UTC).
|
||||
|
||||
goto V Migrate to version V
|
||||
up [N] Apply all or N up migrations
|
||||
down [N] Apply all or N down migrations
|
||||
drop Drop everything inside database
|
||||
down [N] [-all] Apply all or N down migrations
|
||||
Use -all to apply all down migrations
|
||||
drop [-f] Drop everything inside database
|
||||
Use -f to bypass confirmation
|
||||
force V Set version V but don't run migration (ignores dirty state)
|
||||
version Print current migration version
|
||||
```
|
||||
|
||||
@@ -7,14 +7,12 @@ import (
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/golang-migrate/migrate/v4/database/multistmt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -199,14 +197,14 @@ func (c *Cassandra) Close() error {
|
||||
}
|
||||
|
||||
func (c *Cassandra) Lock() error {
|
||||
if !c.isLocked.CAS(false, true) {
|
||||
if !c.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cassandra) Unlock() error {
|
||||
if !c.isLocked.CAS(true, false) {
|
||||
if !c.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -316,11 +314,7 @@ func (c *Cassandra) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := c.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -342,7 +336,7 @@ func parseConsistency(consistencyStr string) (consistency gocql.Consistency, err
|
||||
var ok bool
|
||||
err, ok = r.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("Failed to parse consistency \"%s\": %v", consistencyStr, r)
|
||||
err = fmt.Errorf("failed to parse consistency \"%s\": %v", consistencyStr, r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
# ClickHouse
|
||||
|
||||
`clickhouse://host:port?username=user&password=password&database=clicks&x-multi-statement=true`
|
||||
|
||||
| URL Query | Description |
|
||||
|------------|-------------|
|
||||
| `x-migrations-table`| Name of the migrations table |
|
||||
| `x-migrations-table-engine`| Engine to use for the migrations table, defaults to TinyLog |
|
||||
| `x-cluster-name` | Name of cluster for creating `schema_migrations` table cluster wide |
|
||||
| `database` | The name of the database to connect to |
|
||||
| `username` | The user to sign in as |
|
||||
| `password` | The user's password |
|
||||
| `host` | The host to connect to. |
|
||||
| `port` | The port to bind to. |
|
||||
| `x-multi-statement` | false | Enable multiple statements to be ran in a single migration (See note below) |
|
||||
|
||||
## Notes
|
||||
|
||||
* The Clickhouse driver does not natively support executing multiple statements in a single query. To allow for multiple statements in a single migration, you can use the `x-multi-statement` param. There are two important caveats:
|
||||
* This mode splits the migration text into separately-executed statements by a semi-colon `;`. Thus `x-multi-statement` cannot be used when a statement in the migration contains a string with a semi-colon.
|
||||
* The queries are not executed in any sort of transaction/batch, meaning you are responsible for fixing partial migrations.
|
||||
* Using the default TinyLog table engine for the schema_versions table prevents backing up the table if using the [clickhouse-backup](https://github.com/AlexAkulov/clickhouse-backup) tool. If backing up the database with make sure the migrations are run with `x-migrations-table-engine=MergeTree`.
|
||||
* Clickhouse cluster mode is not officially supported, since it's not tested right now, but you can try enabling `schema_migrations` table replication by specifying a `x-cluster-name`:
|
||||
* When `x-cluster-name` is specified, `x-migrations-table-engine` also should be specified. See the docs regarding [replicated table engines](https://clickhouse.tech/docs/en/engines/table-engines/mergetree-family/replication/#table_engines-replication).
|
||||
* When `x-cluster-name` is specified, only the `schema_migrations` table is replicated across the cluster. You still need to write your migrations so that the application tables are replicated within the cluster.
|
||||
* If you want to create database inside the migration, you should know, that table which will manage migrations `schema-migrations table` will be in `default` table, so you can't use `USE <database_name>` inside migration. In this case you may not specify the database in the connection string (example you can find [here](examples/migrations/003_create_database.up.sql))
|
||||
@@ -3,18 +3,18 @@ package cockroachdb
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/cockroachdb/cockroach-go/v2/crdb"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/lib/pq"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -161,7 +161,7 @@ func (c *CockroachDb) Lock() error {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := rows.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -276,7 +276,7 @@ func (c *CockroachDb) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -318,11 +318,7 @@ func (c *CockroachDb) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := c.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Datastore
|
||||
|
||||
`datastore://host:port?username=user&password=password&database=clicks&x-multi-statement=true`
|
||||
|
||||
Hanzo Datastore is a ClickHouse-wire-compatible database engine. This driver
|
||||
connects through the native `github.com/hanzo-ds/go` driver, which registers the
|
||||
`database/sql` driver name `datastore`.
|
||||
|
||||
| URL Query | Description |
|
||||
|------------|-------------|
|
||||
| `x-migrations-table`| Name of the migrations table |
|
||||
| `x-migrations-table-engine`| Engine to use for the migrations table, defaults to TinyLog |
|
||||
| `x-cluster-name` | Name of cluster for creating `schema_migrations` table cluster wide |
|
||||
| `x-multi-statement` | Enable multiple statements to be ran in a single migration (See note below) |
|
||||
| `x-multi-statement-max-size` | Maximum size of a single migration in bytes when `x-multi-statement` is set (defaults to 10 MB) |
|
||||
| `database` | The name of the database to connect to |
|
||||
| `username` | The user to sign in as |
|
||||
| `password` | The user's password |
|
||||
| `host` | The host to connect to. |
|
||||
| `port` | The port to bind to. |
|
||||
|
||||
## Notes
|
||||
|
||||
* The Datastore driver does not natively support executing multiple statements in a single query. To allow for multiple statements in a single migration, you can use the `x-multi-statement` param. There are two important caveats:
|
||||
* This mode splits the migration text into separately-executed statements by a semi-colon `;`. Thus `x-multi-statement` cannot be used when a statement in the migration contains a string with a semi-colon.
|
||||
* The queries are not executed in any sort of transaction/batch, meaning you are responsible for fixing partial migrations.
|
||||
* Using the default TinyLog table engine for the `schema_migrations` table prevents backing up the table. If you need to back up the database, run the migrations with `x-migrations-table-engine=MergeTree`.
|
||||
* Datastore cluster mode is not officially supported, but you can try enabling `schema_migrations` table replication by specifying a `x-cluster-name`:
|
||||
* When `x-cluster-name` is specified, `x-migrations-table-engine` also should be specified.
|
||||
* When `x-cluster-name` is specified, only the `schema_migrations` table is replicated across the cluster. You still need to write your migrations so that the application tables are replicated within the cluster.
|
||||
* If you want to create a database inside a migration, note that the `schema_migrations` table will live in the `default` database, so you cannot use `USE <database_name>` inside a migration. In this case you may omit the database in the connection string (example [here](examples/migrations/003_create_database.up.sql)).
|
||||
@@ -1,25 +1,43 @@
|
||||
package clickhouse
|
||||
// Package datastore implements the golang-migrate database.Driver interface for
|
||||
// Hanzo Datastore (a ClickHouse-wire-compatible database engine). It registers
|
||||
// the "datastore://" URL scheme and connects through the native
|
||||
// github.com/hanzo-ds/go driver, which registers the database/sql driver name
|
||||
// "datastore".
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// import _ "github.com/golang-migrate/migrate/v4/database/datastore"
|
||||
//
|
||||
// Then use a URL like:
|
||||
//
|
||||
// datastore://host:9000?username=default&database=default&x-multi-statement=true
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/golang-migrate/migrate/v4/database/multistmt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
||||
// Registers the "datastore" database/sql driver (ClickHouse-wire native).
|
||||
_ "github.com/hanzo-ds/go"
|
||||
)
|
||||
|
||||
var (
|
||||
multiStmtDelimiter = []byte(";")
|
||||
|
||||
// DriverName is the database/sql driver registered by github.com/hanzo-ds/go.
|
||||
DriverName = "datastore"
|
||||
|
||||
DefaultMigrationsTable = "schema_migrations"
|
||||
DefaultMigrationsTableEngine = "TinyLog"
|
||||
DefaultMultiStatementMaxSize = 10 * 1 << 20 // 10 MB
|
||||
@@ -37,9 +55,11 @@ type Config struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
database.Register("clickhouse", &ClickHouse{})
|
||||
database.Register("datastore", &Datastore{})
|
||||
}
|
||||
|
||||
// WithInstance creates a Datastore driver from an existing *sql.DB opened
|
||||
// against the "datastore" driver.
|
||||
func WithInstance(conn *sql.DB, config *Config) (database.Driver, error) {
|
||||
if config == nil {
|
||||
return nil, ErrNilConfig
|
||||
@@ -49,32 +69,34 @@ func WithInstance(conn *sql.DB, config *Config) (database.Driver, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch := &ClickHouse{
|
||||
ds := &Datastore{
|
||||
conn: conn,
|
||||
config: config,
|
||||
}
|
||||
|
||||
if err := ch.init(); err != nil {
|
||||
if err := ds.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ch, nil
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
type ClickHouse struct {
|
||||
// Datastore is a golang-migrate database.Driver backed by the native
|
||||
// github.com/hanzo-ds/go ClickHouse-wire driver.
|
||||
type Datastore struct {
|
||||
conn *sql.DB
|
||||
config *Config
|
||||
isLocked atomic.Bool
|
||||
}
|
||||
|
||||
func (ch *ClickHouse) Open(dsn string) (database.Driver, error) {
|
||||
func (ds *Datastore) Open(dsn string) (database.Driver, error) {
|
||||
purl, err := url.Parse(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q := migrate.FilterCustomQuery(purl)
|
||||
q.Scheme = "tcp"
|
||||
conn, err := sql.Open("clickhouse", q.String())
|
||||
q.Scheme = DriverName
|
||||
conn, err := sql.Open(DriverName, q.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,7 +114,7 @@ func (ch *ClickHouse) Open(dsn string) (database.Driver, error) {
|
||||
migrationsTableEngine = s
|
||||
}
|
||||
|
||||
ch = &ClickHouse{
|
||||
ds = &Datastore{
|
||||
conn: conn,
|
||||
config: &Config{
|
||||
MigrationsTable: purl.Query().Get("x-migrations-table"),
|
||||
@@ -104,44 +126,44 @@ func (ch *ClickHouse) Open(dsn string) (database.Driver, error) {
|
||||
},
|
||||
}
|
||||
|
||||
if err := ch.init(); err != nil {
|
||||
if err := ds.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ch, nil
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
func (ch *ClickHouse) init() error {
|
||||
if len(ch.config.DatabaseName) == 0 {
|
||||
if err := ch.conn.QueryRow("SELECT currentDatabase()").Scan(&ch.config.DatabaseName); err != nil {
|
||||
func (ds *Datastore) init() error {
|
||||
if len(ds.config.DatabaseName) == 0 {
|
||||
if err := ds.conn.QueryRow("SELECT currentDatabase()").Scan(&ds.config.DatabaseName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(ch.config.MigrationsTable) == 0 {
|
||||
ch.config.MigrationsTable = DefaultMigrationsTable
|
||||
if len(ds.config.MigrationsTable) == 0 {
|
||||
ds.config.MigrationsTable = DefaultMigrationsTable
|
||||
}
|
||||
|
||||
if ch.config.MultiStatementMaxSize <= 0 {
|
||||
ch.config.MultiStatementMaxSize = DefaultMultiStatementMaxSize
|
||||
if ds.config.MultiStatementMaxSize <= 0 {
|
||||
ds.config.MultiStatementMaxSize = DefaultMultiStatementMaxSize
|
||||
}
|
||||
|
||||
if len(ch.config.MigrationsTableEngine) == 0 {
|
||||
ch.config.MigrationsTableEngine = DefaultMigrationsTableEngine
|
||||
if len(ds.config.MigrationsTableEngine) == 0 {
|
||||
ds.config.MigrationsTableEngine = DefaultMigrationsTableEngine
|
||||
}
|
||||
|
||||
return ch.ensureVersionTable()
|
||||
return ds.ensureVersionTable()
|
||||
}
|
||||
|
||||
func (ch *ClickHouse) Run(r io.Reader) error {
|
||||
if ch.config.MultiStatementEnabled {
|
||||
func (ds *Datastore) Run(r io.Reader) error {
|
||||
if ds.config.MultiStatementEnabled {
|
||||
var err error
|
||||
if e := multistmt.Parse(r, multiStmtDelimiter, ch.config.MultiStatementMaxSize, func(m []byte) bool {
|
||||
if e := multistmt.Parse(r, multiStmtDelimiter, ds.config.MultiStatementMaxSize, func(m []byte) bool {
|
||||
tq := strings.TrimSpace(string(m))
|
||||
if tq == "" {
|
||||
return true
|
||||
}
|
||||
if _, e := ch.conn.Exec(string(m)); e != nil {
|
||||
if _, e := ds.conn.Exec(string(m)); e != nil {
|
||||
err = database.Error{OrigErr: e, Err: "migration failed", Query: m}
|
||||
return false
|
||||
}
|
||||
@@ -157,19 +179,20 @@ func (ch *ClickHouse) Run(r io.Reader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := ch.conn.Exec(string(migration)); err != nil {
|
||||
if _, err := ds.conn.Exec(string(migration)); err != nil {
|
||||
return database.Error{OrigErr: err, Err: "migration failed", Query: migration}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (ch *ClickHouse) Version() (int, bool, error) {
|
||||
|
||||
func (ds *Datastore) Version() (int, bool, error) {
|
||||
var (
|
||||
version int
|
||||
dirty uint8
|
||||
query = "SELECT version, dirty FROM `" + ch.config.MigrationsTable + "` ORDER BY sequence DESC LIMIT 1"
|
||||
query = "SELECT version, dirty FROM `" + ds.config.MigrationsTable + "` ORDER BY sequence DESC LIMIT 1"
|
||||
)
|
||||
if err := ch.conn.QueryRow(query).Scan(&version, &dirty); err != nil {
|
||||
if err := ds.conn.QueryRow(query).Scan(&version, &dirty); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return database.NilVersion, false, nil
|
||||
}
|
||||
@@ -178,7 +201,7 @@ func (ch *ClickHouse) Version() (int, bool, error) {
|
||||
return version, dirty == 1, nil
|
||||
}
|
||||
|
||||
func (ch *ClickHouse) SetVersion(version int, dirty bool) error {
|
||||
func (ds *Datastore) SetVersion(version int, dirty bool) error {
|
||||
var (
|
||||
bool = func(v bool) uint8 {
|
||||
if v {
|
||||
@@ -186,13 +209,13 @@ func (ch *ClickHouse) SetVersion(version int, dirty bool) error {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
tx, err = ch.conn.Begin()
|
||||
tx, err = ds.conn.Begin()
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := "INSERT INTO " + ch.config.MigrationsTable + " (version, dirty, sequence) VALUES (?, ?, ?)"
|
||||
query := "INSERT INTO " + ds.config.MigrationsTable + " (version, dirty, sequence) VALUES (?, ?, ?)"
|
||||
if _, err := tx.Exec(query, version, bool(dirty), time.Now().UnixNano()); err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -202,28 +225,24 @@ func (ch *ClickHouse) SetVersion(version int, dirty bool) error {
|
||||
|
||||
// ensureVersionTable checks if versions table exists and, if not, creates it.
|
||||
// Note that this function locks the database, which deviates from the usual
|
||||
// convention of "caller locks" in the ClickHouse type.
|
||||
func (ch *ClickHouse) ensureVersionTable() (err error) {
|
||||
if err = ch.Lock(); err != nil {
|
||||
// convention of "caller locks" in the Datastore type.
|
||||
func (ds *Datastore) ensureVersionTable() (err error) {
|
||||
if err = ds.Lock(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if e := ch.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
if e := ds.Unlock(); e != nil {
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
var (
|
||||
table string
|
||||
query = "SHOW TABLES FROM " + quoteIdentifier(ch.config.DatabaseName) + " LIKE '" + ch.config.MigrationsTable + "'"
|
||||
query = "SHOW TABLES FROM " + quoteIdentifier(ds.config.DatabaseName) + " LIKE '" + ds.config.MigrationsTable + "'"
|
||||
)
|
||||
// check if migration table exists
|
||||
if err := ch.conn.QueryRow(query).Scan(&table); err != nil {
|
||||
if err := ds.conn.QueryRow(query).Scan(&table); err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -232,42 +251,42 @@ func (ch *ClickHouse) ensureVersionTable() (err error) {
|
||||
}
|
||||
|
||||
// if not, create the empty migration table
|
||||
if len(ch.config.ClusterName) > 0 {
|
||||
if len(ds.config.ClusterName) > 0 {
|
||||
query = fmt.Sprintf(`
|
||||
CREATE TABLE %s ON CLUSTER %s (
|
||||
version Int64,
|
||||
dirty UInt8,
|
||||
sequence UInt64
|
||||
) Engine=%s`, ch.config.MigrationsTable, ch.config.ClusterName, ch.config.MigrationsTableEngine)
|
||||
) Engine=%s`, ds.config.MigrationsTable, ds.config.ClusterName, ds.config.MigrationsTableEngine)
|
||||
} else {
|
||||
query = fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
version Int64,
|
||||
dirty UInt8,
|
||||
sequence UInt64
|
||||
) Engine=%s`, ch.config.MigrationsTable, ch.config.MigrationsTableEngine)
|
||||
) Engine=%s`, ds.config.MigrationsTable, ds.config.MigrationsTableEngine)
|
||||
}
|
||||
|
||||
if strings.HasSuffix(ch.config.MigrationsTableEngine, "Tree") {
|
||||
if strings.HasSuffix(ds.config.MigrationsTableEngine, "Tree") {
|
||||
query = fmt.Sprintf(`%s ORDER BY sequence`, query)
|
||||
}
|
||||
|
||||
if _, err := ch.conn.Exec(query); err != nil {
|
||||
if _, err := ds.conn.Exec(query); err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch *ClickHouse) Drop() (err error) {
|
||||
query := "SHOW TABLES FROM " + quoteIdentifier(ch.config.DatabaseName)
|
||||
tables, err := ch.conn.Query(query)
|
||||
func (ds *Datastore) Drop() (err error) {
|
||||
query := "SHOW TABLES FROM " + quoteIdentifier(ds.config.DatabaseName)
|
||||
tables, err := ds.conn.Query(query)
|
||||
|
||||
if err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -277,9 +296,9 @@ func (ch *ClickHouse) Drop() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
query = "DROP TABLE IF EXISTS " + quoteIdentifier(ch.config.DatabaseName) + "." + quoteIdentifier(table)
|
||||
query = "DROP TABLE IF EXISTS " + quoteIdentifier(ds.config.DatabaseName) + "." + quoteIdentifier(table)
|
||||
|
||||
if _, err := ch.conn.Exec(query); err != nil {
|
||||
if _, err := ds.conn.Exec(query); err != nil {
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
}
|
||||
@@ -290,21 +309,23 @@ func (ch *ClickHouse) Drop() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch *ClickHouse) Lock() error {
|
||||
if !ch.isLocked.CAS(false, true) {
|
||||
func (ds *Datastore) Lock() error {
|
||||
if !ds.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (ch *ClickHouse) Unlock() error {
|
||||
if !ch.isLocked.CAS(true, false) {
|
||||
|
||||
func (ds *Datastore) Unlock() error {
|
||||
if !ds.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (ch *ClickHouse) Close() error { return ch.conn.Close() }
|
||||
|
||||
func (ds *Datastore) Close() error { return ds.conn.Close() }
|
||||
|
||||
// Copied from lib/pq implementation: https://github.com/lib/pq/blob/v1.9.0/conn.go#L1611
|
||||
func quoteIdentifier(name string) string {
|
||||
@@ -312,5 +333,5 @@ func quoteIdentifier(name string) string {
|
||||
if end > -1 {
|
||||
name = name[:end]
|
||||
}
|
||||
return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
|
||||
return `"` + strings.ReplaceAll(name, `"`, `""`) + `"`
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package clickhouse_test
|
||||
package datastore_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -8,13 +8,15 @@ import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
_ "github.com/ClickHouse/clickhouse-go"
|
||||
"github.com/dhui/dktest"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/clickhouse"
|
||||
"github.com/golang-migrate/migrate/v4/database/datastore"
|
||||
dt "github.com/golang-migrate/migrate/v4/database/testing"
|
||||
"github.com/golang-migrate/migrate/v4/dktesting"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
|
||||
// Registers the "datastore" database/sql driver (ClickHouse-wire native).
|
||||
_ "github.com/hanzo-ds/go"
|
||||
)
|
||||
|
||||
const defaultPort = 9000
|
||||
@@ -26,19 +28,19 @@ var (
|
||||
PortRequired: true, ReadyFunc: isReady,
|
||||
}
|
||||
specs = []dktesting.ContainerSpec{
|
||||
{ImageName: "yandex/clickhouse-server:21.3", Options: opts},
|
||||
{ImageName: "clickhouse:24.8", Options: opts},
|
||||
}
|
||||
)
|
||||
|
||||
func clickhouseConnectionString(host, port, engine string) string {
|
||||
func datastoreConnectionString(host, port, engine string) string {
|
||||
if engine != "" {
|
||||
return fmt.Sprintf(
|
||||
"clickhouse://%v:%v?username=user&password=password&database=db&x-multi-statement=true&x-migrations-table-engine=%v&debug=false",
|
||||
"datastore://%v:%v?username=user&password=password&database=db&x-multi-statement=true&x-migrations-table-engine=%v&debug=false",
|
||||
host, port, engine)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"clickhouse://%v:%v?username=user&password=password&database=db&x-multi-statement=true&debug=false",
|
||||
"datastore://%v:%v?username=user&password=password&database=db&x-multi-statement=true&debug=false",
|
||||
host, port)
|
||||
}
|
||||
|
||||
@@ -48,7 +50,7 @@ func isReady(ctx context.Context, c dktest.ContainerInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
db, err := sql.Open("clickhouse", clickhouseConnectionString(ip, port, ""))
|
||||
db, err := sql.Open("datastore", datastoreConnectionString(ip, port, ""))
|
||||
|
||||
if err != nil {
|
||||
log.Println("open error", err)
|
||||
@@ -90,8 +92,8 @@ func testSimple(t *testing.T, engine string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr := clickhouseConnectionString(ip, port, engine)
|
||||
p := &clickhouse.ClickHouse{}
|
||||
addr := datastoreConnectionString(ip, port, engine)
|
||||
p := &datastore.Datastore{}
|
||||
d, err := p.Open(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -113,12 +115,12 @@ func testSimpleWithInstanceDefaultConfigValues(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr := clickhouseConnectionString(ip, port, "")
|
||||
conn, err := sql.Open("clickhouse", addr)
|
||||
addr := datastoreConnectionString(ip, port, "")
|
||||
conn, err := sql.Open("datastore", addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d, err := clickhouse.WithInstance(conn, &clickhouse.Config{})
|
||||
d, err := datastore.WithInstance(conn, &datastore.Config{})
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
t.Fatal(err)
|
||||
@@ -140,8 +142,8 @@ func testMigrate(t *testing.T, engine string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr := clickhouseConnectionString(ip, port, engine)
|
||||
p := &clickhouse.ClickHouse{}
|
||||
addr := datastoreConnectionString(ip, port, engine)
|
||||
p := &datastore.Datastore{}
|
||||
d, err := p.Open(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -169,8 +171,8 @@ func testVersion(t *testing.T, engine string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr := clickhouseConnectionString(ip, port, engine)
|
||||
p := &clickhouse.ClickHouse{}
|
||||
addr := datastoreConnectionString(ip, port, engine)
|
||||
p := &datastore.Datastore{}
|
||||
d, err := p.Open(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -204,8 +206,8 @@ func testDrop(t *testing.T, engine string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr := clickhouseConnectionString(ip, port, engine)
|
||||
p := &clickhouse.ClickHouse{}
|
||||
addr := datastoreConnectionString(ip, port, engine)
|
||||
p := &datastore.Datastore{}
|
||||
d, err := p.Open(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
CREATE TABLE test_1 (
|
||||
Date Date
|
||||
Date Date
|
||||
) Engine=Memory;
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
CREATE TABLE test_2 (
|
||||
Date Date
|
||||
Date Date
|
||||
) Engine=Memory;
|
||||
@@ -1,20 +1,19 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package firebird
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
_ "github.com/nakagami/firebirdsql"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -108,14 +107,14 @@ func (f *Firebird) Close() error {
|
||||
}
|
||||
|
||||
func (f *Firebird) Lock() error {
|
||||
if !f.isLocked.CAS(false, true) {
|
||||
if !f.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Firebird) Unlock() error {
|
||||
if !f.isLocked.CAS(true, false) {
|
||||
if !f.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -181,7 +180,7 @@ func (f *Firebird) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -224,11 +223,7 @@ func (f *Firebird) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := f.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -38,8 +38,9 @@ var (
|
||||
},
|
||||
}
|
||||
specs = []dktesting.ContainerSpec{
|
||||
{ImageName: "jacobalberty/firebird:2.5-ss", Options: opts},
|
||||
{ImageName: "jacobalberty/firebird:3.0", Options: opts},
|
||||
{ImageName: "jacobalberty/firebird:v3.0", Options: opts},
|
||||
{ImageName: "jacobalberty/firebird:v4.0", Options: opts},
|
||||
{ImageName: "jacobalberty/firebird:v5.0", Options: opts},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -2,21 +2,21 @@ package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/x/mongo/driver/connstring"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -325,11 +325,7 @@ func (m *Mongo) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := m.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ var (
|
||||
opts = dktest.Options{PortRequired: true, ReadyFunc: isReady}
|
||||
// Supported versions: https://www.mongodb.com/support-policy
|
||||
specs = []dktesting.ContainerSpec{
|
||||
{ImageName: "mongo:3.4", Options: opts},
|
||||
{ImageName: "mongo:3.6", Options: opts},
|
||||
{ImageName: "mongo:4.0", Options: opts},
|
||||
{ImageName: "mongo:4.2", Options: opts},
|
||||
{ImageName: "mongo:5.0", Options: opts},
|
||||
{ImageName: "mongo:6.0", Options: opts},
|
||||
{ImageName: "mongo:7.0", Options: opts},
|
||||
{ImageName: "mongo:8.0", Options: opts},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
+7
-13
@@ -1,5 +1,4 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package mysql
|
||||
|
||||
@@ -8,19 +7,18 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
var _ database.Driver = (*Mysql)(nil) // explicit compile time type check
|
||||
@@ -36,7 +34,7 @@ var (
|
||||
ErrNilConfig = fmt.Errorf("no config")
|
||||
ErrNoDatabaseName = fmt.Errorf("no database name")
|
||||
ErrAppendPEM = fmt.Errorf("failed to append PEM")
|
||||
ErrTLSCertKeyConfig = fmt.Errorf("To use TLS client authentication, both x-tls-cert and x-tls-key must not be empty")
|
||||
ErrTLSCertKeyConfig = fmt.Errorf("to use TLS client authentication, both x-tls-cert and x-tls-key must not be empty")
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -364,7 +362,7 @@ func (m *Mysql) SetVersion(version int, dirty bool) error {
|
||||
query := "DELETE FROM `" + m.config.MigrationsTable + "` LIMIT 1"
|
||||
if _, err := tx.ExecContext(context.Background(), query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -376,7 +374,7 @@ func (m *Mysql) SetVersion(version int, dirty bool) error {
|
||||
query := "INSERT INTO `" + m.config.MigrationsTable + "` (version, dirty) VALUES (?, ?)"
|
||||
if _, err := tx.ExecContext(context.Background(), query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -418,7 +416,7 @@ func (m *Mysql) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -471,11 +469,7 @@ func (m *Mysql) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := m.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package neo4j
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
neturl "net/url"
|
||||
@@ -10,7 +11,6 @@ import (
|
||||
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/golang-migrate/migrate/v4/database/multistmt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/neo4j/neo4j-go-driver/neo4j"
|
||||
)
|
||||
|
||||
@@ -141,7 +141,7 @@ func (n *Neo4j) Run(migration io.Reader) (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if cerr := session.Close(); cerr != nil {
|
||||
err = multierror.Append(err, cerr)
|
||||
err = errors.Join(err, cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -188,7 +188,7 @@ func (n *Neo4j) SetVersion(version int, dirty bool) (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if cerr := session.Close(); cerr != nil {
|
||||
err = multierror.Append(err, cerr)
|
||||
err = errors.Join(err, cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -213,7 +213,7 @@ func (n *Neo4j) Version() (version int, dirty bool, err error) {
|
||||
}
|
||||
defer func() {
|
||||
if cerr := session.Close(); cerr != nil {
|
||||
err = multierror.Append(err, cerr)
|
||||
err = errors.Join(err, cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -261,7 +261,7 @@ func (n *Neo4j) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if cerr := session.Close(); cerr != nil {
|
||||
err = multierror.Append(err, cerr)
|
||||
err = errors.Join(err, cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -278,7 +278,7 @@ func (n *Neo4j) ensureVersionConstraint() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if cerr := session.Close(); cerr != nil {
|
||||
err = multierror.Append(err, cerr)
|
||||
err = errors.Join(err, cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
+12
-18
@@ -1,25 +1,23 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package pgx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/golang-migrate/migrate/v4/database/multistmt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/jackc/pgconn"
|
||||
"github.com/jackc/pgerrcode"
|
||||
_ "github.com/jackc/pgx/v4/stdlib"
|
||||
@@ -183,7 +181,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
|
||||
if s := purl.Query().Get("x-migrations-table-quoted"); len(s) > 0 {
|
||||
migrationsTableQuoted, err = strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse option x-migrations-table-quoted: %w", err)
|
||||
return nil, fmt.Errorf("unable to parse option x-migrations-table-quoted: %w", err)
|
||||
}
|
||||
}
|
||||
if (len(migrationsTable) > 0) && (migrationsTableQuoted) && ((migrationsTable[0] != '"') || (migrationsTable[len(migrationsTable)-1] != '"')) {
|
||||
@@ -214,7 +212,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
|
||||
if s := purl.Query().Get("x-multi-statement"); len(s) > 0 {
|
||||
multiStatementEnabled, err = strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse option x-multi-statement: %w", err)
|
||||
return nil, fmt.Errorf("unable to parse option x-multi-statement: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +295,7 @@ func (p *Postgres) applyTableLock() error {
|
||||
defer func() {
|
||||
errRollback := tx.Rollback()
|
||||
if errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -314,7 +312,7 @@ func (p *Postgres) applyTableLock() error {
|
||||
|
||||
defer func() {
|
||||
if errClose := rows.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -414,7 +412,7 @@ func (p *Postgres) runStatement(statement []byte) error {
|
||||
|
||||
func computeLineFromPos(s string, pos int) (line uint, col uint, ok bool) {
|
||||
// replace crlf with lf
|
||||
s = strings.Replace(s, "\r\n", "\n", -1)
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
// pg docs: pos uses index 1 for the first character, and positions are measured in characters not bytes
|
||||
runes := []rune(s)
|
||||
if pos > len(runes) {
|
||||
@@ -456,7 +454,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
|
||||
query := `TRUNCATE ` + quoteIdentifier(p.config.migrationsSchemaName) + `.` + quoteIdentifier(p.config.migrationsTableName)
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -468,7 +466,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
|
||||
query = `INSERT INTO ` + quoteIdentifier(p.config.migrationsSchemaName) + `.` + quoteIdentifier(p.config.migrationsTableName) + ` (version, dirty) VALUES ($1, $2)`
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -510,7 +508,7 @@ func (p *Postgres) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -558,11 +556,7 @@ func (p *Postgres) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := p.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -619,5 +613,5 @@ func quoteIdentifier(name string) string {
|
||||
if end > -1 {
|
||||
name = name[:end]
|
||||
}
|
||||
return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
|
||||
return `"` + strings.ReplaceAll(name, `"`, `""`) + `"`
|
||||
}
|
||||
|
||||
@@ -755,10 +755,10 @@ func Test_computeLineFromPos(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
input := tc.input
|
||||
if crlf {
|
||||
input = strings.Replace(input, "\n", "\r\n", -1)
|
||||
input = strings.ReplaceAll(input, "\n", "\r\n")
|
||||
}
|
||||
if nonASCII {
|
||||
input = strings.Replace(input, "FROM", "FRÖM", -1)
|
||||
input = strings.ReplaceAll(input, "FROM", "FRÖM")
|
||||
}
|
||||
gotLine, gotCol, gotOK := computeLineFromPos(input, tc.pos)
|
||||
|
||||
|
||||
+10
-16
@@ -1,25 +1,23 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package pgx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/golang-migrate/migrate/v4/database/multistmt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/jackc/pgerrcode"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
@@ -159,7 +157,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
|
||||
if s := purl.Query().Get("x-migrations-table-quoted"); len(s) > 0 {
|
||||
migrationsTableQuoted, err = strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse option x-migrations-table-quoted: %w", err)
|
||||
return nil, fmt.Errorf("unable to parse option x-migrations-table-quoted: %w", err)
|
||||
}
|
||||
}
|
||||
if (len(migrationsTable) > 0) && (migrationsTableQuoted) && ((migrationsTable[0] != '"') || (migrationsTable[len(migrationsTable)-1] != '"')) {
|
||||
@@ -190,7 +188,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
|
||||
if s := purl.Query().Get("x-multi-statement"); len(s) > 0 {
|
||||
multiStatementEnabled, err = strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse option x-multi-statement: %w", err)
|
||||
return nil, fmt.Errorf("unable to parse option x-multi-statement: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +303,7 @@ func (p *Postgres) runStatement(statement []byte) error {
|
||||
|
||||
func computeLineFromPos(s string, pos int) (line uint, col uint, ok bool) {
|
||||
// replace crlf with lf
|
||||
s = strings.Replace(s, "\r\n", "\n", -1)
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
// pg docs: pos uses index 1 for the first character, and positions are measured in characters not bytes
|
||||
runes := []rune(s)
|
||||
if pos > len(runes) {
|
||||
@@ -347,7 +345,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
|
||||
query := `TRUNCATE ` + quoteIdentifier(p.config.migrationsSchemaName) + `.` + quoteIdentifier(p.config.migrationsTableName)
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -359,7 +357,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
|
||||
query = `INSERT INTO ` + quoteIdentifier(p.config.migrationsSchemaName) + `.` + quoteIdentifier(p.config.migrationsTableName) + ` (version, dirty) VALUES ($1, $2)`
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -401,7 +399,7 @@ func (p *Postgres) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -443,11 +441,7 @@ func (p *Postgres) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := p.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -482,5 +476,5 @@ func quoteIdentifier(name string) string {
|
||||
if end > -1 {
|
||||
name = name[:end]
|
||||
}
|
||||
return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
|
||||
return `"` + strings.ReplaceAll(name, `"`, `""`) + `"`
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ var (
|
||||
PortRequired: true, ReadyFunc: isReady}
|
||||
// Supported versions: https://www.postgresql.org/support/versioning/
|
||||
specs = []dktesting.ContainerSpec{
|
||||
{ImageName: "postgres:12", Options: opts},
|
||||
{ImageName: "postgres:13", Options: opts},
|
||||
{ImageName: "postgres:14", Options: opts},
|
||||
{ImageName: "postgres:15", Options: opts},
|
||||
{ImageName: "postgres:16", Options: opts},
|
||||
{ImageName: "postgres:17", Options: opts},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -730,10 +730,10 @@ func Test_computeLineFromPos(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
input := tc.input
|
||||
if crlf {
|
||||
input = strings.Replace(input, "\n", "\r\n", -1)
|
||||
input = strings.ReplaceAll(input, "\n", "\r\n")
|
||||
}
|
||||
if nonASCII {
|
||||
input = strings.Replace(input, "FROM", "FRÖM", -1)
|
||||
input = strings.ReplaceAll(input, "FROM", "FRÖM")
|
||||
}
|
||||
gotLine, gotCol, gotOK := computeLineFromPos(input, tc.pos)
|
||||
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/golang-migrate/migrate/v4/database/multistmt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
@@ -167,7 +165,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
|
||||
if s := purl.Query().Get("x-migrations-table-quoted"); len(s) > 0 {
|
||||
migrationsTableQuoted, err = strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse option x-migrations-table-quoted: %w", err)
|
||||
return nil, fmt.Errorf("unable to parse option x-migrations-table-quoted: %w", err)
|
||||
}
|
||||
}
|
||||
if (len(migrationsTable) > 0) && (migrationsTableQuoted) && ((migrationsTable[0] != '"') || (migrationsTable[len(migrationsTable)-1] != '"')) {
|
||||
@@ -198,7 +196,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) {
|
||||
if s := purl.Query().Get("x-multi-statement"); len(s) > 0 {
|
||||
multiStatementEnabled, err = strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse option x-multi-statement: %w", err)
|
||||
return nil, fmt.Errorf("unable to parse option x-multi-statement: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +319,7 @@ func (p *Postgres) runStatement(statement []byte) error {
|
||||
|
||||
func computeLineFromPos(s string, pos int) (line uint, col uint, ok bool) {
|
||||
// replace crlf with lf
|
||||
s = strings.Replace(s, "\r\n", "\n", -1)
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
// pg docs: pos uses index 1 for the first character, and positions are measured in characters not bytes
|
||||
runes := []rune(s)
|
||||
if pos > len(runes) {
|
||||
@@ -363,7 +361,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
|
||||
query := `TRUNCATE ` + pq.QuoteIdentifier(p.config.migrationsSchemaName) + `.` + pq.QuoteIdentifier(p.config.migrationsTableName)
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -375,7 +373,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
|
||||
query = `INSERT INTO ` + pq.QuoteIdentifier(p.config.migrationsSchemaName) + `.` + pq.QuoteIdentifier(p.config.migrationsTableName) + ` (version, dirty) VALUES ($1, $2)`
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -417,7 +415,7 @@ func (p *Postgres) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -459,11 +457,7 @@ func (p *Postgres) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := p.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -798,10 +798,10 @@ func Test_computeLineFromPos(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
input := tc.input
|
||||
if crlf {
|
||||
input = strings.Replace(input, "\n", "\r\n", -1)
|
||||
input = strings.ReplaceAll(input, "\n", "\r\n")
|
||||
}
|
||||
if nonASCII {
|
||||
input = strings.Replace(input, "FROM", "FRÖM", -1)
|
||||
input = strings.ReplaceAll(input, "FROM", "FRÖM")
|
||||
}
|
||||
gotLine, gotCol, gotOK := computeLineFromPos(input, tc.pos)
|
||||
|
||||
|
||||
+8
-13
@@ -2,13 +2,12 @@ package ql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
@@ -72,11 +71,7 @@ func (m *Ql) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := m.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -133,7 +128,7 @@ func (m *Ql) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -166,13 +161,13 @@ func (m *Ql) Drop() (err error) {
|
||||
return nil
|
||||
}
|
||||
func (m *Ql) Lock() error {
|
||||
if !m.isLocked.CAS(false, true) {
|
||||
if !m.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Ql) Unlock() error {
|
||||
if !m.isLocked.CAS(true, false) {
|
||||
if !m.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -193,7 +188,7 @@ func (m *Ql) executeQuery(query string) error {
|
||||
}
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -221,7 +216,7 @@ func (m *Ql) SetVersion(version int, dirty bool) error {
|
||||
m.config.MigrationsTable)
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package redshift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
@@ -128,14 +126,14 @@ func (p *Redshift) Close() error {
|
||||
|
||||
// Redshift does not support advisory lock functions: https://docs.aws.amazon.com/redshift/latest/dg/c_unsupported-postgresql-functions.html
|
||||
func (p *Redshift) Lock() error {
|
||||
if !p.isLocked.CAS(false, true) {
|
||||
if !p.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Redshift) Unlock() error {
|
||||
if !p.isLocked.CAS(true, false) {
|
||||
if !p.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -176,7 +174,7 @@ func (p *Redshift) Run(migration io.Reader) error {
|
||||
|
||||
func computeLineFromPos(s string, pos int) (line uint, col uint, ok bool) {
|
||||
// replace crlf with lf
|
||||
s = strings.Replace(s, "\r\n", "\n", -1)
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
// pg docs: pos uses index 1 for the first character, and positions are measured in characters not bytes
|
||||
runes := []rune(s)
|
||||
if pos > len(runes) {
|
||||
@@ -218,7 +216,7 @@ func (p *Redshift) SetVersion(version int, dirty bool) error {
|
||||
query := `DELETE FROM "` + p.config.MigrationsTable + `"`
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -230,7 +228,7 @@ func (p *Redshift) SetVersion(version int, dirty bool) error {
|
||||
query = `INSERT INTO "` + p.config.MigrationsTable + `" (version, dirty) VALUES ($1, $2)`
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -272,7 +270,7 @@ func (p *Redshift) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -314,11 +312,7 @@ func (p *Redshift) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := p.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -378,10 +378,10 @@ func Test_computeLineFromPos(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
input := tc.input
|
||||
if crlf {
|
||||
input = strings.Replace(input, "\n", "\r\n", -1)
|
||||
input = strings.ReplaceAll(input, "\n", "\r\n")
|
||||
}
|
||||
if nonASCII {
|
||||
input = strings.Replace(input, "FROM", "FRÖM", -1)
|
||||
input = strings.ReplaceAll(input, "FROM", "FRÖM")
|
||||
}
|
||||
gotLine, gotCol, gotOK := computeLineFromPos(input, tc.pos)
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package rqlite
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rqlite/gorqlite"
|
||||
)
|
||||
|
||||
@@ -90,11 +88,7 @@ func (r *Rqlite) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := r.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -144,7 +138,7 @@ func (r *Rqlite) Close() error {
|
||||
// If the implementation can't provide this functionality, return nil.
|
||||
// Return database.ErrLocked if database is already locked.
|
||||
func (r *Rqlite) Lock() error {
|
||||
if !r.isLocked.CAS(false, true) {
|
||||
if !r.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
@@ -153,7 +147,7 @@ func (r *Rqlite) Lock() error {
|
||||
// Unlock should release the lock. Migrate will call this function after
|
||||
// all migrations have been run.
|
||||
func (r *Rqlite) Unlock() error {
|
||||
if !r.isLocked.CAS(true, false) {
|
||||
if !r.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -292,7 +286,7 @@ func parseUrl(url string) (*nurl.URL, *Config, error) {
|
||||
}
|
||||
|
||||
if parsedUrl.Scheme != "rqlite" {
|
||||
return nil, nil, errors.Wrap(ErrBadConfig, "bad scheme")
|
||||
return nil, nil, fmt.Errorf("bad scheme: %w", ErrBadConfig)
|
||||
}
|
||||
|
||||
// adapt from rqlite to http/https schemes
|
||||
@@ -316,7 +310,7 @@ func parseConfigFromQuery(queryVals nurl.Values) (*Config, error) {
|
||||
migrationsTable := queryVals.Get("x-migrations-table")
|
||||
if migrationsTable != "" {
|
||||
if strings.HasPrefix(migrationsTable, "sqlite_") {
|
||||
return nil, errors.Wrap(ErrBadConfig, "invalid value for x-migrations-table")
|
||||
return nil, fmt.Errorf("invalid value for x-migrations-table: %w", ErrBadConfig)
|
||||
}
|
||||
c.MigrationsTable = migrationsTable
|
||||
}
|
||||
@@ -325,7 +319,7 @@ func parseConfigFromQuery(queryVals nurl.Values) (*Config, error) {
|
||||
if connectInsecureStr != "" {
|
||||
connectInsecure, err := strconv.ParseBool(connectInsecureStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrBadConfig, "invalid value for x-connect-insecure")
|
||||
return nil, fmt.Errorf("invalid value for x-connect-insecure: %w", ErrBadConfig)
|
||||
}
|
||||
c.ConnectInsecure = connectInsecure
|
||||
}
|
||||
|
||||
@@ -3,16 +3,15 @@ package snowflake
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/lib/pq"
|
||||
sf "github.com/snowflakedb/gosnowflake"
|
||||
)
|
||||
@@ -159,14 +158,14 @@ func (p *Snowflake) Close() error {
|
||||
}
|
||||
|
||||
func (p *Snowflake) Lock() error {
|
||||
if !p.isLocked.CAS(false, true) {
|
||||
if !p.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Snowflake) Unlock() error {
|
||||
if !p.isLocked.CAS(true, false) {
|
||||
if !p.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -207,7 +206,7 @@ func (p *Snowflake) Run(migration io.Reader) error {
|
||||
|
||||
func computeLineFromPos(s string, pos int) (line uint, col uint, ok bool) {
|
||||
// replace crlf with lf
|
||||
s = strings.Replace(s, "\r\n", "\n", -1)
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
// pg docs: pos uses index 1 for the first character, and positions are measured in characters not bytes
|
||||
runes := []rune(s)
|
||||
if pos > len(runes) {
|
||||
@@ -249,7 +248,7 @@ func (p *Snowflake) SetVersion(version int, dirty bool) error {
|
||||
query := `DELETE FROM "` + p.config.MigrationsTable + `"`
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -263,7 +262,7 @@ func (p *Snowflake) SetVersion(version int, dirty bool) error {
|
||||
` + strconv.FormatBool(dirty) + `)`
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -305,7 +304,7 @@ func (p *Snowflake) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -347,11 +346,7 @@ func (p *Snowflake) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := p.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"cloud.google.com/go/spanner"
|
||||
sdb "cloud.google.com/go/spanner/admin/database/apiv1"
|
||||
@@ -19,8 +20,6 @@ import (
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
|
||||
adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
uatomic "go.uber.org/atomic"
|
||||
"google.golang.org/api/iterator"
|
||||
)
|
||||
|
||||
@@ -32,11 +31,6 @@ func init() {
|
||||
// DefaultMigrationsTable is used if no custom table is specified
|
||||
const DefaultMigrationsTable = "SchemaMigrations"
|
||||
|
||||
const (
|
||||
unlockedVal = 0
|
||||
lockedVal = 1
|
||||
)
|
||||
|
||||
// Driver errors
|
||||
var (
|
||||
ErrNilConfig = errors.New("no config")
|
||||
@@ -64,7 +58,7 @@ type Spanner struct {
|
||||
|
||||
config *Config
|
||||
|
||||
lock *uatomic.Uint32
|
||||
lock atomic.Bool
|
||||
}
|
||||
|
||||
type DB struct {
|
||||
@@ -96,7 +90,6 @@ func WithInstance(instance *DB, config *Config) (database.Driver, error) {
|
||||
sx := &Spanner{
|
||||
db: instance,
|
||||
config: config,
|
||||
lock: uatomic.NewUint32(unlockedVal),
|
||||
}
|
||||
|
||||
if err := sx.ensureVersionTable(); err != nil {
|
||||
@@ -153,7 +146,7 @@ func (s *Spanner) Close() error {
|
||||
// Lock implements database.Driver but doesn't do anything because Spanner only
|
||||
// enqueues the UpdateDatabaseDdlRequest.
|
||||
func (s *Spanner) Lock() error {
|
||||
if swapped := s.lock.CAS(unlockedVal, lockedVal); swapped {
|
||||
if swapped := s.lock.CompareAndSwap(false, true); swapped {
|
||||
return nil
|
||||
}
|
||||
return ErrLockHeld
|
||||
@@ -161,7 +154,7 @@ func (s *Spanner) Lock() error {
|
||||
|
||||
// Unlock implements database.Driver but no action required, see Lock.
|
||||
func (s *Spanner) Unlock() error {
|
||||
if swapped := s.lock.CAS(lockedVal, unlockedVal); swapped {
|
||||
if swapped := s.lock.CompareAndSwap(true, false); swapped {
|
||||
return nil
|
||||
}
|
||||
return ErrLockNotHeld
|
||||
@@ -305,11 +298,7 @@ func (s *Spanner) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := s.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -2,17 +2,16 @@ package sqlcipher
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
_ "github.com/mutecomm/go-sqlcipher/v4"
|
||||
)
|
||||
|
||||
@@ -73,11 +72,7 @@ func (m *Sqlite) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := m.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -141,7 +136,7 @@ func (m *Sqlite) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -178,14 +173,14 @@ func (m *Sqlite) Drop() (err error) {
|
||||
}
|
||||
|
||||
func (m *Sqlite) Lock() error {
|
||||
if !m.isLocked.CAS(false, true) {
|
||||
if !m.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Sqlite) Unlock() error {
|
||||
if !m.isLocked.CAS(true, false) {
|
||||
if !m.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -211,7 +206,7 @@ func (m *Sqlite) executeQuery(query string) error {
|
||||
}
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -246,7 +241,7 @@ func (m *Sqlite) SetVersion(version int, dirty bool) error {
|
||||
query := fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, m.config.MigrationsTable)
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,16 @@ package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
@@ -73,11 +72,7 @@ func (m *Sqlite) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := m.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -141,7 +136,7 @@ func (m *Sqlite) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -178,14 +173,14 @@ func (m *Sqlite) Drop() (err error) {
|
||||
}
|
||||
|
||||
func (m *Sqlite) Lock() error {
|
||||
if !m.isLocked.CAS(false, true) {
|
||||
if !m.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Sqlite) Unlock() error {
|
||||
if !m.isLocked.CAS(true, false) {
|
||||
if !m.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -211,7 +206,7 @@ func (m *Sqlite) executeQuery(query string) error {
|
||||
}
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -246,7 +241,7 @@ func (m *Sqlite) SetVersion(version int, dirty bool) error {
|
||||
query := fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, m.config.MigrationsTable)
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,16 @@ package sqlite3
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
@@ -73,11 +72,7 @@ func (m *Sqlite) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := m.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -141,7 +136,7 @@ func (m *Sqlite) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -178,14 +173,14 @@ func (m *Sqlite) Drop() (err error) {
|
||||
}
|
||||
|
||||
func (m *Sqlite) Lock() error {
|
||||
if !m.isLocked.CAS(false, true) {
|
||||
if !m.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Sqlite) Unlock() error {
|
||||
if !m.isLocked.CAS(true, false) {
|
||||
if !m.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
@@ -211,7 +206,7 @@ func (m *Sqlite) executeQuery(query string) error {
|
||||
}
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -246,7 +241,7 @@ func (m *Sqlite) SetVersion(version int, dirty bool) error {
|
||||
query := fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, m.config.MigrationsTable)
|
||||
if _, err := tx.Exec(query, version, dirty); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,17 @@ package sqlserver
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
nurl "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
mssql "github.com/microsoft/go-mssqldb" // mssql support
|
||||
)
|
||||
|
||||
@@ -30,10 +29,10 @@ var (
|
||||
ErrNoDatabaseName = fmt.Errorf("no database name")
|
||||
ErrNoSchema = fmt.Errorf("no schema")
|
||||
ErrDatabaseDirty = fmt.Errorf("database is dirty")
|
||||
ErrMultipleAuthOptionsPassed = fmt.Errorf("both password and useMsi=true were passed.")
|
||||
ErrMultipleAuthOptionsPassed = fmt.Errorf("both password and useMsi=true were passed")
|
||||
)
|
||||
|
||||
var lockErrorMap = map[mssql.ReturnStatus]string{
|
||||
var lockErrorMap = map[int]string{
|
||||
-1: "The lock request timed out.",
|
||||
-2: "The lock request was canceled.",
|
||||
-3: "The lock request was chosen as a deadlock victim.",
|
||||
@@ -198,18 +197,24 @@ func (ss *SQLServer) Lock() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// This will either obtain the lock immediately and return true,
|
||||
// or return false if the lock cannot be acquired immediately.
|
||||
// This will block until the lock is acquired.
|
||||
// MS Docs: sp_getapplock: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-getapplock-transact-sql?view=sql-server-2017
|
||||
query := `EXEC sp_getapplock @Resource = @p1, @LockMode = 'Update', @LockOwner = 'Session', @LockTimeout = 0`
|
||||
query := `
|
||||
DECLARE @lockResult int;
|
||||
EXEC @lockResult = sp_getapplock @Resource = @p1, @LockMode = 'Exclusive', @LockOwner = 'Session', @LockTimeout = -1;
|
||||
SELECT @lockResult;`
|
||||
|
||||
var status mssql.ReturnStatus
|
||||
if _, err = ss.conn.ExecContext(context.Background(), query, aid, &status); err == nil && status > -1 {
|
||||
var status int
|
||||
if err = ss.conn.QueryRowContext(context.Background(), query, aid).Scan(&status); err == nil && status > -1 {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)}
|
||||
} else {
|
||||
return &database.Error{Err: fmt.Sprintf("try lock failed with error %v: %v", status, lockErrorMap[status]), Query: []byte(query)}
|
||||
errorDescription, ok := lockErrorMap[status]
|
||||
if !ok {
|
||||
errorDescription = "Unknown error"
|
||||
}
|
||||
return &database.Error{Err: fmt.Sprintf("try lock failed with error %v: %v", status, errorDescription), Query: []byte(query)}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -266,7 +271,7 @@ func (ss *SQLServer) SetVersion(version int, dirty bool) error {
|
||||
query := `TRUNCATE TABLE ` + ss.getMigrationTable()
|
||||
if _, err := tx.Exec(query); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -282,7 +287,7 @@ func (ss *SQLServer) SetVersion(version int, dirty bool) error {
|
||||
query = `INSERT INTO ` + ss.getMigrationTable() + ` (version, dirty) VALUES (@p1, @p2)`
|
||||
if _, err := tx.Exec(query, version, dirtyBit); err != nil {
|
||||
if errRollback := tx.Rollback(); errRollback != nil {
|
||||
err = multierror.Append(err, errRollback)
|
||||
err = errors.Join(err, errRollback)
|
||||
}
|
||||
return &database.Error{OrigErr: err, Query: []byte(query)}
|
||||
}
|
||||
@@ -354,11 +359,7 @@ func (ss *SQLServer) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := ss.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ package stub
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
)
|
||||
@@ -50,14 +49,14 @@ func (s *Stub) Close() error {
|
||||
}
|
||||
|
||||
func (s *Stub) Lock() error {
|
||||
if !s.isLocked.CAS(false, true) {
|
||||
if !s.isLocked.CompareAndSwap(false, true) {
|
||||
return database.ErrLocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stub) Unlock() error {
|
||||
if !s.isLocked.CAS(true, false) {
|
||||
if !s.isLocked.CompareAndSwap(true, false) {
|
||||
return database.ErrNotLocked
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestLockAndUnlock(t *testing.T, d database.Driver) {
|
||||
case <-done:
|
||||
return
|
||||
case <-timeout:
|
||||
errs <- fmt.Errorf("Timeout after 15 seconds. Looks like a deadlock in Lock/UnLock.\n%#v", d)
|
||||
errs <- fmt.Errorf("timeout after 15 seconds, looks like a deadlock in Lock/UnLock\n%#v", d)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,6 @@ func TestDrop(t *testing.T, d database.Driver) {
|
||||
}
|
||||
|
||||
func TestSetVersion(t *testing.T, d database.Driver) {
|
||||
// nolint:maligned
|
||||
testCases := []struct {
|
||||
name string
|
||||
version int
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@ package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.uber.org/atomic"
|
||||
"hash/crc32"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const advisoryLockIDSalt uint = 1486364155
|
||||
@@ -21,7 +21,7 @@ func GenerateAdvisoryLockId(databaseName string, additionalNames ...string) (str
|
||||
|
||||
// CasRestoreOnErr CAS wrapper to automatically restore the lock state on error
|
||||
func CasRestoreOnErr(lock *atomic.Bool, o, n bool, casErr error, f func() error) error {
|
||||
if !lock.CAS(o, n) {
|
||||
if !lock.CompareAndSwap(o, n) {
|
||||
return casErr
|
||||
}
|
||||
if err := f(); err != nil {
|
||||
|
||||
@@ -2,7 +2,7 @@ package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestCasRestoreOnErr(t *testing.T) {
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
lock *atomic.Bool
|
||||
lock bool
|
||||
from bool
|
||||
to bool
|
||||
expectLock bool
|
||||
@@ -63,7 +63,7 @@ func TestCasRestoreOnErr(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Test positive CAS lock",
|
||||
lock: atomic.NewBool(false),
|
||||
lock: false,
|
||||
from: false,
|
||||
to: true,
|
||||
expectLock: true,
|
||||
@@ -72,7 +72,7 @@ func TestCasRestoreOnErr(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Test negative CAS lock",
|
||||
lock: atomic.NewBool(true),
|
||||
lock: true,
|
||||
from: false,
|
||||
to: true,
|
||||
expectLock: true,
|
||||
@@ -81,7 +81,7 @@ func TestCasRestoreOnErr(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Test negative with callback lock",
|
||||
lock: atomic.NewBool(false),
|
||||
lock: false,
|
||||
from: false,
|
||||
to: true,
|
||||
expectLock: false,
|
||||
@@ -92,13 +92,15 @@ func TestCasRestoreOnErr(t *testing.T) {
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if err := CasRestoreOnErr(tc.lock, tc.from, tc.to, casErr, func() error {
|
||||
var lock atomic.Bool
|
||||
lock.Store(tc.lock)
|
||||
if err := CasRestoreOnErr(&lock, tc.from, tc.to, casErr, func() error {
|
||||
return tc.fErr
|
||||
}); err != tc.expectError {
|
||||
t.Error("Incorrect error value returned")
|
||||
}
|
||||
|
||||
if tc.lock.Load() != tc.expectLock {
|
||||
if lock.Load() != tc.expectLock {
|
||||
t.Error("Incorrect state of lock")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -8,16 +8,15 @@ import (
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/jackc/pgconn"
|
||||
"github.com/jackc/pgerrcode"
|
||||
"github.com/lib/pq"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -206,7 +205,7 @@ func (c *YugabyteDB) Lock() error {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := rows.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -320,7 +319,7 @@ func (c *YugabyteDB) Drop() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := tables.Close(); errClose != nil {
|
||||
err = multierror.Append(err, errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -360,11 +359,7 @@ func (c *YugabyteDB) ensureVersionTable() (err error) {
|
||||
|
||||
defer func() {
|
||||
if e := c.Unlock(); e != nil {
|
||||
if err == nil {
|
||||
err = e
|
||||
} else {
|
||||
err = multierror.Append(err, e)
|
||||
}
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -420,8 +415,9 @@ func (c *YugabyteDB) doTxWithRetry(
|
||||
}
|
||||
|
||||
// If we've tried to commit the transaction Rollback just returns sql.ErrTxDone.
|
||||
//nolint:errcheck
|
||||
defer tx.Rollback()
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if err := fn(tx); err != nil {
|
||||
if errIsRetryable(err) {
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
module github.com/golang-migrate/migrate/v4
|
||||
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.23.1
|
||||
go 1.26.4
|
||||
|
||||
require (
|
||||
cloud.google.com/go/spanner v1.56.0
|
||||
cloud.google.com/go/storage v1.38.0
|
||||
cloud.google.com/go/spanner v1.85.0
|
||||
cloud.google.com/go/storage v1.56.0
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.16
|
||||
github.com/ClickHouse/clickhouse-go v1.4.3
|
||||
github.com/aws/aws-sdk-go v1.49.6
|
||||
github.com/cenkalti/backoff/v4 v4.1.2
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.1.1
|
||||
github.com/dhui/dktest v0.4.4
|
||||
github.com/docker/docker v27.2.0+incompatible
|
||||
github.com/dhui/dktest v0.4.6
|
||||
github.com/docker/docker v28.3.3+incompatible
|
||||
github.com/fsouza/fake-gcs-server v1.17.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gobuffalo/here v0.6.0
|
||||
github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556
|
||||
github.com/google/go-github/v39 v39.2.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hanzo-ds/go v1.0.1
|
||||
github.com/jackc/pgconn v1.14.3
|
||||
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
|
||||
github.com/jackc/pgx/v4 v4.18.2
|
||||
github.com/jackc/pgx/v5 v5.5.4
|
||||
github.com/jackc/pgx/v5 v5.7.6
|
||||
github.com/ktrysmt/go-bitbucket v0.6.4
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/markbates/pkger v0.15.1
|
||||
@@ -33,47 +30,67 @@ require (
|
||||
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8
|
||||
github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba
|
||||
github.com/snowflakedb/gosnowflake v1.6.19
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/xanzy/go-gitlab v0.15.0
|
||||
go.mongodb.org/mongo-driver v1.7.5
|
||||
go.uber.org/atomic v1.7.0
|
||||
golang.org/x/oauth2 v0.18.0
|
||||
golang.org/x/tools v0.24.0
|
||||
google.golang.org/api v0.169.0
|
||||
go.mongodb.org/mongo-driver v1.11.4
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated
|
||||
google.golang.org/api v0.247.0
|
||||
modernc.org/ql v1.0.0
|
||||
modernc.org/sqlite v1.18.1
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.4 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-faster/city v1.0.1 // indirect
|
||||
github.com/go-faster/errors v0.7.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/hanzo-ds/native v0.71.0 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
|
||||
go.opentelemetry.io/otel v1.29.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/montanaflynn/stats v0.6.6 // indirect
|
||||
github.com/paulmach/orb v0.12.0 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/segmentio/asm v1.2.1 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.44.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.29.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.44.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.112.1 // indirect
|
||||
cloud.google.com/go/compute v1.25.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.1.6 // indirect
|
||||
cloud.google.com/go/longrunning v0.5.5 // indirect
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
|
||||
github.com/99designs/keyring v1.2.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 // indirect
|
||||
@@ -85,7 +102,7 @@ require (
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/apache/arrow/go/v10 v10.0.1 // indirect
|
||||
github.com/apache/thrift v0.16.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect
|
||||
@@ -101,53 +118,47 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 // indirect
|
||||
github.com/aws/smithy-go v1.13.3 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
|
||||
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369 // indirect
|
||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
|
||||
github.com/dvsekhvalnov/jose2go v1.7.0 // indirect
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.12.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/goccy/go-json v0.9.11 // indirect
|
||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/flatbuffers v2.0.8+incompatible // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.2 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/gorilla/handlers v1.4.2 // indirect
|
||||
github.com/gorilla/mux v1.7.4 // indirect
|
||||
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgtype v1.14.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/k0kubun/pp v2.3.0+incompatible // indirect
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/klauspost/asmfmt v1.3.2 // indirect
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/klauspost/compress v1.18.6 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
@@ -161,13 +172,13 @@ require (
|
||||
github.com/onsi/gomega v1.15.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.16 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.27 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.1 // indirect
|
||||
@@ -176,22 +187,21 @@ require (
|
||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/crypto v0.47.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/term v0.27.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/mod v0.31.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.45.0 // indirect
|
||||
golang.org/x/term v0.39.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect
|
||||
google.golang.org/grpc v1.64.1 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build aws_s3
|
||||
// +build aws_s3
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build bitbucket
|
||||
// +build bitbucket
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build cassandra
|
||||
// +build cassandra
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build clickhouse
|
||||
// +build clickhouse
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
_ "github.com/ClickHouse/clickhouse-go"
|
||||
_ "github.com/golang-migrate/migrate/v4/database/clickhouse"
|
||||
)
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build cockroachdb
|
||||
// +build cockroachdb
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build datastore
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
_ "github.com/golang-migrate/migrate/v4/database/datastore"
|
||||
)
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build firebird
|
||||
// +build firebird
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build github
|
||||
// +build github
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build github
|
||||
// +build github
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build gitlab
|
||||
// +build gitlab
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build go_bindata
|
||||
// +build go_bindata
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build godoc_vfs
|
||||
// +build godoc_vfs
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build google_cloud_storage
|
||||
// +build google_cloud_storage
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build mongodb
|
||||
// +build mongodb
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build mysql
|
||||
// +build mysql
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build neo4j
|
||||
// +build neo4j
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pgx
|
||||
// +build pgx
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pgx5
|
||||
// +build pgx5
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build postgres
|
||||
// +build postgres
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build ql
|
||||
// +build ql
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build redshift
|
||||
// +build redshift
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build rqlite
|
||||
// +build rqlite
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build snowflake
|
||||
// +build snowflake
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build spanner
|
||||
// +build spanner
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build sqlcipher
|
||||
// +build sqlcipher
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build sqlite
|
||||
// +build sqlite
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build sqlite3
|
||||
// +build sqlite3
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build sqlserver
|
||||
// +build sqlserver
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build yugabytedb
|
||||
// +build yugabytedb
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidSequenceWidth = errors.New("Digits must be positive")
|
||||
errIncompatibleSeqAndFormat = errors.New("The seq and format options are mutually exclusive")
|
||||
errInvalidTimeFormat = errors.New("Time format may not be empty")
|
||||
errInvalidSequenceWidth = errors.New("digits must be positive")
|
||||
errIncompatibleSeqAndFormat = errors.New("the seq and format options are mutually exclusive")
|
||||
errInvalidTimeFormat = errors.New("time format may not be empty")
|
||||
)
|
||||
|
||||
func nextSeqVersion(matches []string, seqDigits int) (string, error) {
|
||||
@@ -33,7 +33,7 @@ func nextSeqVersion(matches []string, seqDigits int) (string, error) {
|
||||
idx := strings.Index(matchSeqStr, "_")
|
||||
|
||||
if idx < 1 { // Using 1 instead of 0 since there should be at least 1 digit
|
||||
return "", fmt.Errorf("Malformed migration filename: %s", filename)
|
||||
return "", fmt.Errorf("malformed migration filename: %s", filename)
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -50,7 +50,7 @@ func nextSeqVersion(matches []string, seqDigits int) (string, error) {
|
||||
version := fmt.Sprintf("%0[2]*[1]d", nextSeq, seqDigits)
|
||||
|
||||
if len(version) > seqDigits {
|
||||
return "", fmt.Errorf("Next sequence number %s too large. At most %d digits are allowed", version, seqDigits)
|
||||
return "", fmt.Errorf("next sequence number %s too large, at most %d digits are allowed", version, seqDigits)
|
||||
}
|
||||
|
||||
return version, nil
|
||||
|
||||
@@ -84,17 +84,17 @@ func (s *CreateCmdSuite) TestNextSeqVersion() {
|
||||
}{
|
||||
{"Bad digits", []string{}, 0, "", errInvalidSequenceWidth},
|
||||
{"Single digit initialize", []string{}, 1, "1", nil},
|
||||
{"Single digit malformed", []string{"bad"}, 1, "", errors.New("Malformed migration filename: bad")},
|
||||
{"Single digit malformed", []string{"bad"}, 1, "", errors.New("malformed migration filename: bad")},
|
||||
{"Single digit no int", []string{"bad_bad"}, 1, "", errors.New(`strconv.ParseUint: parsing "bad": invalid syntax`)},
|
||||
{"Single digit negative seq", []string{"-5_test"}, 1, "", errors.New(`strconv.ParseUint: parsing "-5": invalid syntax`)},
|
||||
{"Single digit increment", []string{"3_test", "4_test"}, 1, "5", nil},
|
||||
{"Single digit overflow", []string{"9_test"}, 1, "", errors.New("Next sequence number 10 too large. At most 1 digits are allowed")},
|
||||
{"Single digit overflow", []string{"9_test"}, 1, "", errors.New("next sequence number 10 too large, at most 1 digits are allowed")},
|
||||
{"Zero-pad initialize", []string{}, 6, "000001", nil},
|
||||
{"Zero-pad malformed", []string{"bad"}, 6, "", errors.New("Malformed migration filename: bad")},
|
||||
{"Zero-pad malformed", []string{"bad"}, 6, "", errors.New("malformed migration filename: bad")},
|
||||
{"Zero-pad no int", []string{"bad_bad"}, 6, "", errors.New(`strconv.ParseUint: parsing "bad": invalid syntax`)},
|
||||
{"Zero-pad negative seq", []string{"-000005_test"}, 6, "", errors.New(`strconv.ParseUint: parsing "-000005": invalid syntax`)},
|
||||
{"Zero-pad increment", []string{"000003_test", "000004_test"}, 6, "000005", nil},
|
||||
{"Zero-pad overflow", []string{"999999_test"}, 6, "", errors.New("Next sequence number 1000000 too large. At most 6 digits are allowed")},
|
||||
{"Zero-pad overflow", []string{"999999_test"}, 6, "", errors.New("next sequence number 1000000 too large, at most 6 digits are allowed")},
|
||||
{"dir absolute path", []string{"/migrationDir/000001_test"}, 6, "000002", nil},
|
||||
{"dir relative path", []string{"migrationDir/000001_test"}, 6, "000002", nil},
|
||||
{"dir dot prefix", []string{"./migrationDir/000001_test"}, 6, "000002", nil},
|
||||
@@ -188,11 +188,11 @@ func (s *CreateCmdSuite) TestCreateCmd() {
|
||||
{"seq init dir double dot relative trailing slash", []string{"subdir"}, "subdir", nil, []string{"subdir/0001_name.up.sql", "subdir/0001_name.down.sql"}, nil, "../subdir/", ts, defaultTimeFormat, true, 4, "sql", "name"},
|
||||
{"seq init dir maze", []string{"subdir"}, "subdir", nil, []string{"0001_name.up.sql", "0001_name.down.sql"}, nil, "..//subdir/./.././/subdir/..", ts, defaultTimeFormat, true, 4, "sql", "name"},
|
||||
{"seq width invalid", nil, "", nil, nil, errInvalidSequenceWidth, ".", ts, defaultTimeFormat, true, 0, "sql", "name"},
|
||||
{"seq malformed", nil, "", []string{"bad.sql"}, []string{"bad.sql"}, errors.New("Malformed migration filename: bad.sql"), ".", ts, defaultTimeFormat, true, 4, "sql", "name"},
|
||||
{"seq malformed", nil, "", []string{"bad.sql"}, []string{"bad.sql"}, errors.New("malformed migration filename: bad.sql"), ".", ts, defaultTimeFormat, true, 4, "sql", "name"},
|
||||
{"seq not int", nil, "", []string{"bad_bad.sql"}, []string{"bad_bad.sql"}, errors.New(`strconv.ParseUint: parsing "bad": invalid syntax`), ".", ts, defaultTimeFormat, true, 4, "sql", "name"},
|
||||
{"seq negative", nil, "", []string{"-5_negative.sql"}, []string{"-5_negative.sql"}, errors.New(`strconv.ParseUint: parsing "-5": invalid syntax`), ".", ts, defaultTimeFormat, true, 4, "sql", "name"},
|
||||
{"seq increment", nil, "", []string{"3_three.sql", "4_four.sql"}, []string{"3_three.sql", "4_four.sql", "0005_five.up.sql", "0005_five.down.sql"}, nil, ".", ts, defaultTimeFormat, true, 4, "sql", "five"},
|
||||
{"seq overflow", nil, "", []string{"9_nine.sql"}, []string{"9_nine.sql"}, errors.New(`Next sequence number 10 too large. At most 1 digits are allowed`), ".", ts, defaultTimeFormat, true, 1, "sql", "ten"},
|
||||
{"seq overflow", nil, "", []string{"9_nine.sql"}, []string{"9_nine.sql"}, errors.New(`next sequence number 10 too large, at most 1 digits are allowed`), ".", ts, defaultTimeFormat, true, 1, "sql", "ten"},
|
||||
{"time empty format", nil, "", nil, nil, errInvalidTimeFormat, ".", ts, "", false, 0, "sql", "name"},
|
||||
{"time unix", nil, "", nil, []string{tsUnixStr + "_name.up.sql", tsUnixStr + "_name.down.sql"}, nil, ".", ts, "unix", false, 0, "sql", "name"},
|
||||
{"time unixNano", nil, "", nil, []string{tsUnixNanoStr + "_name.up.sql", tsUnixNanoStr + "_name.down.sql"}, nil, ".", ts, "unixNano", false, 0, "sql", "name"},
|
||||
|
||||
+19
-21
@@ -11,8 +11,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4/database"
|
||||
iurl "github.com/golang-migrate/migrate/v4/internal/url"
|
||||
"github.com/golang-migrate/migrate/v4/source"
|
||||
@@ -56,10 +54,10 @@ func (e ErrDirty) Error() string {
|
||||
}
|
||||
|
||||
type Migrate struct {
|
||||
sourceName string
|
||||
sourceDrv source.Driver
|
||||
databaseName string
|
||||
databaseDrv database.Driver
|
||||
sourceName string
|
||||
sourceDrv source.Driver
|
||||
databaseDriverName string
|
||||
databaseDrv database.Driver
|
||||
|
||||
// Log accepts a Logger interface
|
||||
Log Logger
|
||||
@@ -93,11 +91,11 @@ func New(sourceURL, databaseURL string) (*Migrate, error) {
|
||||
}
|
||||
m.sourceName = sourceName
|
||||
|
||||
databaseName, err := iurl.SchemeFromURL(databaseURL)
|
||||
databaseDriverName, err := iurl.SchemeFromURL(databaseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse scheme from database URL: %w", err)
|
||||
}
|
||||
m.databaseName = databaseName
|
||||
m.databaseDriverName = databaseDriverName
|
||||
|
||||
sourceDrv, err := source.Open(sourceURL)
|
||||
if err != nil {
|
||||
@@ -116,9 +114,9 @@ func New(sourceURL, databaseURL string) (*Migrate, error) {
|
||||
|
||||
// NewWithDatabaseInstance returns a new Migrate instance from a source URL
|
||||
// and an existing database instance. The source URL scheme is defined by each driver.
|
||||
// Use any string that can serve as an identifier during logging as databaseName.
|
||||
// Use any string that can serve as an identifier during logging as databaseDriverName.
|
||||
// You are responsible for closing the underlying database client if necessary.
|
||||
func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInstance database.Driver) (*Migrate, error) {
|
||||
func NewWithDatabaseInstance(sourceURL string, databaseDriverName string, databaseInstance database.Driver) (*Migrate, error) {
|
||||
m := newCommon()
|
||||
|
||||
sourceName, err := iurl.SchemeFromURL(sourceURL)
|
||||
@@ -127,7 +125,7 @@ func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInst
|
||||
}
|
||||
m.sourceName = sourceName
|
||||
|
||||
m.databaseName = databaseName
|
||||
m.databaseDriverName = databaseDriverName
|
||||
|
||||
sourceDrv, err := source.Open(sourceURL)
|
||||
if err != nil {
|
||||
@@ -147,11 +145,11 @@ func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInst
|
||||
func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, databaseURL string) (*Migrate, error) {
|
||||
m := newCommon()
|
||||
|
||||
databaseName, err := iurl.SchemeFromURL(databaseURL)
|
||||
databaseDriverName, err := iurl.SchemeFromURL(databaseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse scheme from database URL: %w", err)
|
||||
}
|
||||
m.databaseName = databaseName
|
||||
m.databaseDriverName = databaseDriverName
|
||||
|
||||
m.sourceName = sourceName
|
||||
|
||||
@@ -168,13 +166,13 @@ func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, data
|
||||
|
||||
// NewWithInstance returns a new Migrate instance from an existing source and
|
||||
// database instance. Use any string that can serve as an identifier during logging
|
||||
// as sourceName and databaseName. You are responsible for closing down
|
||||
// as sourceName and databaseDriverName. You are responsible for closing down
|
||||
// the underlying source and database client if necessary.
|
||||
func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseName string, databaseInstance database.Driver) (*Migrate, error) {
|
||||
func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseDriverName string, databaseInstance database.Driver) (*Migrate, error) {
|
||||
m := newCommon()
|
||||
|
||||
m.sourceName = sourceName
|
||||
m.databaseName = databaseName
|
||||
m.databaseDriverName = databaseDriverName
|
||||
|
||||
m.sourceDrv = sourceInstance
|
||||
m.databaseDrv = databaseInstance
|
||||
@@ -526,7 +524,7 @@ func (m *Migrate) read(from int, to int, ret chan<- interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// readUp reads up migrations from `from` limitted by `limit`.
|
||||
// readUp reads up migrations from `from` limited by `limit`.
|
||||
// limit can be -1, implying no limit and reading until there are no more migrations.
|
||||
// Each migration is then written to the ret channel.
|
||||
// If an error occurs during reading, that error is written to the ret channel, too.
|
||||
@@ -626,7 +624,7 @@ func (m *Migrate) readUp(from int, limit int, ret chan<- interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// readDown reads down migrations from `from` limitted by `limit`.
|
||||
// readDown reads down migrations from `from` limited by `limit`.
|
||||
// limit can be -1, implying no limit and reading until there are no more migrations.
|
||||
// Each migration is then written to the ret channel.
|
||||
// If an error occurs during reading, that error is written to the ret channel, too.
|
||||
@@ -781,7 +779,7 @@ func (m *Migrate) versionExists(version uint) (result error) {
|
||||
if err == nil {
|
||||
defer func() {
|
||||
if errClose := up.Close(); errClose != nil {
|
||||
result = multierror.Append(result, errClose)
|
||||
result = errors.Join(result, errClose)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -796,7 +794,7 @@ func (m *Migrate) versionExists(version uint) (result error) {
|
||||
if err == nil {
|
||||
defer func() {
|
||||
if errClose := down.Close(); errClose != nil {
|
||||
result = multierror.Append(result, errClose)
|
||||
result = errors.Join(result, errClose)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -954,7 +952,7 @@ func (m *Migrate) unlock() error {
|
||||
// if a prevErr is not nil.
|
||||
func (m *Migrate) unlockErr(prevErr error) error {
|
||||
if err := m.unlock(); err != nil {
|
||||
return multierror.Append(prevErr, err)
|
||||
prevErr = errors.Join(prevErr, err)
|
||||
}
|
||||
return prevErr
|
||||
}
|
||||
|
||||
+8
-13
@@ -54,8 +54,8 @@ func TestNew(t *testing.T) {
|
||||
t.Error("expected sourceDrv not to be nil")
|
||||
}
|
||||
|
||||
if m.databaseName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseName)
|
||||
if m.databaseDriverName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseDriverName)
|
||||
}
|
||||
if m.databaseDrv == nil {
|
||||
t.Error("expected databaseDrv not to be nil")
|
||||
@@ -94,8 +94,8 @@ func TestNewWithDatabaseInstance(t *testing.T) {
|
||||
t.Error("expected sourceDrv not to be nil")
|
||||
}
|
||||
|
||||
if m.databaseName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseName)
|
||||
if m.databaseDriverName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseDriverName)
|
||||
}
|
||||
if m.databaseDrv == nil {
|
||||
t.Error("expected databaseDrv not to be nil")
|
||||
@@ -153,8 +153,8 @@ func TestNewWithSourceInstance(t *testing.T) {
|
||||
t.Error("expected sourceDrv not to be nil")
|
||||
}
|
||||
|
||||
if m.databaseName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseName)
|
||||
if m.databaseDriverName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseDriverName)
|
||||
}
|
||||
if m.databaseDrv == nil {
|
||||
t.Error("expected databaseDrv not to be nil")
|
||||
@@ -209,8 +209,8 @@ func TestNewWithInstance(t *testing.T) {
|
||||
t.Error("expected sourceDrv not to be nil")
|
||||
}
|
||||
|
||||
if m.databaseName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseName)
|
||||
if m.databaseDriverName != dbDrvNameStub {
|
||||
t.Errorf("expected stub, got %v", m.databaseDriverName)
|
||||
}
|
||||
if m.databaseDrv == nil {
|
||||
t.Error("expected databaseDrv not to be nil")
|
||||
@@ -1339,11 +1339,6 @@ func newMigSeq(migr ...*Migration) migrationSequence {
|
||||
return migr
|
||||
}
|
||||
|
||||
func (m *migrationSequence) add(migr ...*Migration) migrationSequence { // nolint:unused
|
||||
*m = append(*m, migr...)
|
||||
return *m
|
||||
}
|
||||
|
||||
func (m *migrationSequence) bodySequence() []string {
|
||||
r := make([]string, 0)
|
||||
for _, v := range *m {
|
||||
|
||||
+17
-12
@@ -2,6 +2,7 @@ package migrate
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
@@ -118,7 +119,7 @@ func (m *Migration) LogString() string {
|
||||
|
||||
// Buffer buffers Body up to BufferSize.
|
||||
// Calling this function blocks. Call with goroutine.
|
||||
func (m *Migration) Buffer() error {
|
||||
func (m *Migration) Buffer() (berr error) {
|
||||
if m.Body == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -127,6 +128,21 @@ func (m *Migration) Buffer() error {
|
||||
|
||||
b := bufio.NewReaderSize(m.Body, int(m.BufferSize))
|
||||
|
||||
// defer closing buffer writer and body.
|
||||
defer func() {
|
||||
// close bufferWriter so Buffer knows that there is no
|
||||
// more data coming.
|
||||
if err := m.bufferWriter.Close(); err != nil {
|
||||
berr = errors.Join(berr, err)
|
||||
}
|
||||
|
||||
// it's safe to close the Body too.
|
||||
if err := m.Body.Close(); err != nil {
|
||||
berr = errors.Join(berr, err)
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
// start reading from body, peek won't move the read pointer though
|
||||
// poor man's solution?
|
||||
if _, err := b.Peek(int(m.BufferSize)); err != nil && err != io.EOF {
|
||||
@@ -145,16 +161,5 @@ func (m *Migration) Buffer() error {
|
||||
m.FinishedReading = time.Now()
|
||||
m.BytesRead = n
|
||||
|
||||
// close bufferWriter so Buffer knows that there is no
|
||||
// more data coming
|
||||
if err := m.bufferWriter.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// it's safe to close the Body too
|
||||
if err := m.Body.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ func (g *Gitlab) readDirectory() error {
|
||||
if response.CurrentPage >= response.TotalPages {
|
||||
break
|
||||
}
|
||||
g.listOptions.ListOptions.Page = response.NextPage
|
||||
g.listOptions.Page = response.NextPage
|
||||
}
|
||||
|
||||
for i := range nodes {
|
||||
|
||||
@@ -27,5 +27,5 @@ func New(fs http.FileSystem, path string) (source.Driver, error) {
|
||||
// Open completes the implementetion of source.Driver interface. Other methods
|
||||
// are implemented by the embedded PartialDriver struct.
|
||||
func (d *driver) Open(url string) (source.Driver, error) {
|
||||
return nil, errors.New("Open() cannot be called on the httpfs passthrough driver")
|
||||
return nil, errors.New("open() cannot be called on the httpfs passthrough driver")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package iofs_test
|
||||
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package iofs
|
||||
|
||||
@@ -30,7 +29,7 @@ func New(fsys fs.FS, path string) (source.Driver, error) {
|
||||
// Open is part of source.Driver interface implementation.
|
||||
// Open cannot be called on the iofs passthrough driver.
|
||||
func (d *driver) Open(url string) (source.Driver, error) {
|
||||
return nil, errors.New("Open() cannot be called on the iofs passthrough driver")
|
||||
return nil, errors.New("open() cannot be called on the iofs passthrough driver")
|
||||
}
|
||||
|
||||
// PartialDriver is a helper service for creating new source drivers working with
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package iofs_test
|
||||
|
||||
|
||||
+18
-21
@@ -15,12 +15,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
dockercontainer "github.com/docker/docker/api/types/container"
|
||||
dockerimage "github.com/docker/docker/api/types/image"
|
||||
dockernetwork "github.com/docker/docker/api/types/network"
|
||||
dockerclient "github.com/docker/docker/client"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
func NewDockerContainer(t testing.TB, image string, env []string, cmd []string) (*DockerContainer, error) {
|
||||
@@ -64,14 +62,14 @@ type DockerContainer struct {
|
||||
Cmd []string
|
||||
ContainerId string
|
||||
ContainerName string
|
||||
ContainerJSON dockertypes.ContainerJSON
|
||||
ContainerJSON dockercontainer.InspectResponse
|
||||
containerInspected bool
|
||||
keepForDebugging bool
|
||||
}
|
||||
|
||||
func (d *DockerContainer) PullImage() (err error) {
|
||||
if d == nil {
|
||||
return errors.New("Cannot pull image on a nil *DockerContainer")
|
||||
return errors.New("cannot pull image on a nil *DockerContainer")
|
||||
}
|
||||
d.t.Logf("Docker: Pull image %v", d.ImageName)
|
||||
r, err := d.client.ImagePull(context.Background(), d.ImageName, dockerimage.PullOptions{})
|
||||
@@ -80,7 +78,7 @@ func (d *DockerContainer) PullImage() (err error) {
|
||||
}
|
||||
defer func() {
|
||||
if errClose := r.Close(); errClose != nil {
|
||||
err = multierror.Append(errClose)
|
||||
err = errors.Join(err, errClose)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -100,7 +98,7 @@ func (d *DockerContainer) PullImage() (err error) {
|
||||
|
||||
func (d *DockerContainer) Start() error {
|
||||
if d == nil {
|
||||
return errors.New("Cannot start a nil *DockerContainer")
|
||||
return errors.New("cannot start a nil *DockerContainer")
|
||||
}
|
||||
|
||||
containerName := fmt.Sprintf("migrate_test_%s", pseudoRandStr(10))
|
||||
@@ -148,7 +146,7 @@ func (d *DockerContainer) KeepForDebugging() {
|
||||
|
||||
func (d *DockerContainer) Remove() error {
|
||||
if d == nil {
|
||||
return errors.New("Cannot remove a nil *DockerContainer")
|
||||
return errors.New("cannot remove a nil *DockerContainer")
|
||||
}
|
||||
|
||||
if d.keepForDebugging {
|
||||
@@ -171,7 +169,7 @@ func (d *DockerContainer) Remove() error {
|
||||
|
||||
func (d *DockerContainer) Inspect() error {
|
||||
if d == nil {
|
||||
return errors.New("Cannot inspect a nil *DockerContainer")
|
||||
return errors.New("cannot inspect a nil *DockerContainer")
|
||||
}
|
||||
|
||||
if len(d.ContainerId) == 0 {
|
||||
@@ -189,7 +187,7 @@ func (d *DockerContainer) Inspect() error {
|
||||
|
||||
func (d *DockerContainer) Logs() (io.ReadCloser, error) {
|
||||
if d == nil {
|
||||
return nil, errors.New("Cannot view logs for a nil *DockerContainer")
|
||||
return nil, errors.New("cannot view logs for a nil *DockerContainer")
|
||||
}
|
||||
if len(d.ContainerId) == 0 {
|
||||
return nil, errors.New("missing containerId")
|
||||
@@ -201,7 +199,7 @@ func (d *DockerContainer) Logs() (io.ReadCloser, error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (d *DockerContainer) portMapping(selectFirst bool, cPort int) (containerPort uint, hostIP string, hostPort uint, err error) { // nolint:unparam
|
||||
func (d *DockerContainer) portMapping(selectFirst bool, cPort int) (hostIP string, hostPort uint, err error) {
|
||||
if !d.containerInspected {
|
||||
if err := d.Inspect(); err != nil {
|
||||
d.t.Fatal(err)
|
||||
@@ -213,21 +211,20 @@ func (d *DockerContainer) portMapping(selectFirst bool, cPort int) (containerPor
|
||||
// Skip ahead until we find the port we want
|
||||
continue
|
||||
}
|
||||
for _, binding := range bindings {
|
||||
|
||||
if len(bindings) > 0 {
|
||||
binding := bindings[0]
|
||||
hostPortUint, err := strconv.ParseUint(binding.HostPort, 10, 64)
|
||||
if err != nil {
|
||||
return 0, "", 0, err
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
return uint(port.Int()), binding.HostIP, uint(hostPortUint), nil // nolint: staticcheck
|
||||
return bindings[0].HostIP, uint(hostPortUint), nil
|
||||
}
|
||||
}
|
||||
|
||||
if selectFirst {
|
||||
return 0, "", 0, errors.New("no port binding")
|
||||
return "", 0, errors.New("no port binding")
|
||||
} else {
|
||||
return 0, "", 0, errors.New("specified port not bound")
|
||||
return "", 0, errors.New("specified port not bound")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +232,7 @@ func (d *DockerContainer) Host() string {
|
||||
if d == nil {
|
||||
panic("Cannot get host for a nil *DockerContainer")
|
||||
}
|
||||
_, hostIP, _, err := d.portMapping(true, -1)
|
||||
hostIP, _, err := d.portMapping(true, -1)
|
||||
if err != nil {
|
||||
d.t.Fatal(err)
|
||||
}
|
||||
@@ -251,7 +248,7 @@ func (d *DockerContainer) Port() uint {
|
||||
if d == nil {
|
||||
panic("Cannot get port for a nil *DockerContainer")
|
||||
}
|
||||
_, _, port, err := d.portMapping(true, -1)
|
||||
_, port, err := d.portMapping(true, -1)
|
||||
if err != nil {
|
||||
d.t.Fatal(err)
|
||||
}
|
||||
@@ -262,14 +259,14 @@ func (d *DockerContainer) PortFor(cPort int) uint {
|
||||
if d == nil {
|
||||
panic("Cannot get port for a nil *DockerContainer")
|
||||
}
|
||||
_, _, port, err := d.portMapping(false, cPort)
|
||||
_, port, err := d.portMapping(false, cPort)
|
||||
if err != nil {
|
||||
d.t.Fatal(err)
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func (d *DockerContainer) NetworkSettings() dockertypes.NetworkSettings {
|
||||
func (d *DockerContainer) NetworkSettings() dockercontainer.NetworkSettings {
|
||||
if d == nil {
|
||||
panic("Cannot get network settings for a nil *DockerContainer")
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
dockercontainer "github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
type IsReadyFunc func(Instance) bool
|
||||
@@ -98,6 +98,6 @@ type Instance interface {
|
||||
Host() string
|
||||
Port() uint
|
||||
PortFor(int) uint
|
||||
NetworkSettings() dockertypes.NetworkSettings
|
||||
NetworkSettings() dockercontainer.NetworkSettings
|
||||
KeepForDebugging()
|
||||
}
|
||||
|
||||
@@ -8,14 +8,16 @@ import (
|
||||
|
||||
// MultiError holds multiple errors.
|
||||
//
|
||||
// Deprecated: Use github.com/hashicorp/go-multierror instead
|
||||
// Deprecated: Use stdlib's [errors.Join] et al. instead
|
||||
// This will be removed in the v5 release.
|
||||
type MultiError struct {
|
||||
Errs []error
|
||||
}
|
||||
|
||||
// NewMultiError returns an error type holding multiple errors.
|
||||
//
|
||||
// Deprecated: Use github.com/hashicorp/go-multierror instead
|
||||
// Deprecated: Use stdlib's [errors.Join] et al. instead
|
||||
// This will be removed in the v5 release.
|
||||
func NewMultiError(errs ...error) MultiError {
|
||||
compactErrs := make([]error, 0)
|
||||
for _, e := range errs {
|
||||
|
||||
Reference in New Issue
Block a user