You've already forked go-clickhouse
mirror of
https://github.com/uptrace/go-clickhouse.git
synced 2025-08-10 22:21:30 +02:00
Compare commits
126 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
12a9b1e85d | ||
|
48aa57b286 | ||
|
a4c3d24dfd | ||
|
faaf5d3708 | ||
|
2d9abe8a1a | ||
|
51c9cc65ba | ||
|
e1af2632f1 | ||
|
08021a2c8f | ||
|
03194bc434 | ||
|
13e4911570 | ||
|
c0e67d2ec4 | ||
|
ad9e630abf | ||
|
2d63e3b0ac | ||
|
5cd79b48c3 | ||
|
59dcbc03a4 | ||
|
e4f2453f97 | ||
|
f2100be620 | ||
|
998717a52f | ||
|
318bf373aa | ||
|
479603ef2b | ||
|
06ec956b4a | ||
|
e7b39d844b | ||
|
8aad92b762 | ||
|
e61921245e | ||
|
abe915c5b5 | ||
|
e3920ba190 | ||
|
17b14fa87e | ||
|
a3c6bbc729 | ||
|
44465cd278 | ||
|
b5016bdc7a | ||
|
0f4c06861f | ||
|
3874d74090 | ||
|
117fffe8ed | ||
|
b73c8fabf8 | ||
|
79fddecbb5 | ||
|
92d13a878d | ||
|
0da7ce6381 | ||
|
95a461b824 | ||
|
d073ef0ad6 | ||
|
2830e1daf1 | ||
|
225aa3c101 | ||
|
37984d7ac5 | ||
|
9a58fde149 | ||
|
91f83c5f03 | ||
|
7f26fb6fae | ||
|
2c9485da7f | ||
|
6bfb99e2c1 | ||
|
8bf4958230 | ||
|
546111f030 | ||
|
2b235ce448 | ||
|
83a0bd0a2b | ||
|
7f77517af4 | ||
|
510b9caca8 | ||
|
1e8ca4767f | ||
|
90c25609ec | ||
|
85badc2fe7 | ||
|
988091e532 | ||
|
87e8ceb2a0 | ||
|
0b3639be4e | ||
|
e11b943cfa | ||
|
3ab7cb4325 | ||
|
0e08f4d07a | ||
|
e80d6d288b | ||
|
fd29a667a3 | ||
|
1f5dd92e2a | ||
|
256e92dea4 | ||
|
3b62b36406 | ||
|
032e3a79ba | ||
|
380277d9bc | ||
|
d7b10ec656 | ||
|
f559e06009 | ||
|
1de435ecfb | ||
|
e588da0468 | ||
|
1971cfbba3 | ||
|
0262684d54 | ||
|
9ce0d05f25 | ||
|
83c58b3c5d | ||
|
2321bce7b1 | ||
|
005f04c00b | ||
|
f7545ceda4 | ||
|
1ecd0e65e5 | ||
|
d00947a336 | ||
|
83b354c348 | ||
|
070531e7f3 | ||
|
d101df6f41 | ||
|
83a1943672 | ||
|
d37290b7d2 | ||
|
76504b2778 | ||
|
ed0ec37764 | ||
|
3565a91842 | ||
|
2b6746025b | ||
|
c683e8a787 | ||
|
157546562b | ||
|
3870a5e69c | ||
|
ef260678ec | ||
|
fa44842a34 | ||
|
c439f56e86 | ||
|
a0752b2b5c | ||
|
1543506535 | ||
|
658ad14fc0 | ||
|
c1e00ef235 | ||
|
5ea8b673a3 | ||
|
4360cd8da9 | ||
|
577b338610 | ||
|
bc46507e9a | ||
|
d304da6e36 | ||
|
033c41395a | ||
|
43a65a02e4 | ||
|
c8398f0d25 | ||
|
458b684801 | ||
|
b6446dc0e2 | ||
|
cd94293b45 | ||
|
57d701c4ed | ||
|
69ecbdf5eb | ||
|
99f247ba5e | ||
|
8e25946197 | ||
|
3b4df51456 | ||
|
11bf484562 | ||
|
b880fd0df4 | ||
|
17991b330b | ||
|
29fc6d8609 | ||
|
55950a9534 | ||
|
fd24893ad7 | ||
|
1d7d96e1bb | ||
|
56f9249437 | ||
|
04e796f77e |
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -1,10 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
services:
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:21.12
|
||||
image: clickhouse/clickhouse-server:22.4
|
||||
options: >-
|
||||
--health-cmd "clickhouse-client -q 'select 1'" --health-interval 10s --health-timeout 5s
|
||||
--health-retries 5
|
||||
@@ -22,10 +22,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18.0-beta1
|
||||
stable: false
|
||||
go-version: 1.20.x
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
2
.github/workflows/commitlint.yml
vendored
2
.github/workflows/commitlint.yml
vendored
@@ -8,4 +8,4 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: wagoid/commitlint-github-action@v4
|
||||
- uses: wagoid/commitlint-github-action@v5
|
||||
|
2
.github/workflows/golangci-lint.yml
vendored
2
.github/workflows/golangci-lint.yml
vendored
@@ -16,4 +16,4 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3.1.0
|
||||
uses: golangci/golangci-lint-action@v3.2.0
|
||||
|
121
CHANGELOG.md
121
CHANGELOG.md
@@ -1,3 +1,124 @@
|
||||
## 0.3.1 (2023-02-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* change rollback to always record migrations ([43a65a0](https://github.com/uptrace/go-clickhouse/commit/43a65a02e4ab92bceb846674092bce1a1097bafe))
|
||||
* continue working with non UTC timezone ([033c413](https://github.com/uptrace/go-clickhouse/commit/033c41395a3e7cbbaa25fddc127a1e626a0032b5))
|
||||
* **migrate:** upping was applying zero migrations ([e80d6d2](https://github.com/uptrace/go-clickhouse/commit/e80d6d288b98bcb415e63e31314c0fd1077af668))
|
||||
* move FINAL modifier to the right place ([#52](https://github.com/uptrace/go-clickhouse/issues/52)) ([0f4c068](https://github.com/uptrace/go-clickhouse/commit/0f4c06861f4d2bf5687063a3b52cbf0c3d3b5c4d))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add bfloat16 support ([510b9ca](https://github.com/uptrace/go-clickhouse/commit/510b9caca8b64e62f7a7b12c283be2fcb2761cc5))
|
||||
* add proper Rows implementation and some optimizations ([658ad14](https://github.com/uptrace/go-clickhouse/commit/658ad14fc0f97a2e51e3a113ea7ae0fd77eb2795))
|
||||
* add queries to create/drop views ([b73c8fa](https://github.com/uptrace/go-clickhouse/commit/b73c8fabf8b3292d987803fadd18744872862f53))
|
||||
* add Raw ([1e8ca47](https://github.com/uptrace/go-clickhouse/commit/1e8ca4767fa9a025f87595d95837d87feada4671))
|
||||
* add support for DateTime64 ([c1e00ef](https://github.com/uptrace/go-clickhouse/commit/c1e00ef235a2ebfeebd2bdec52dde9c56ae27544))
|
||||
* add WithAutoCreateDatabase option ([8bf4958](https://github.com/uptrace/go-clickhouse/commit/8bf4958230da026b140f47650c6b78b733160e60))
|
||||
* allow disabling compression for benchmarks ([ef26067](https://github.com/uptrace/go-clickhouse/commit/ef260678ec2acc3fb2c540f8941c4b288d915cdf))
|
||||
* **chmigrate:** add WithReplicated option ([988091e](https://github.com/uptrace/go-clickhouse/commit/988091e532f120f08738f28fb8c620e086d97c41))
|
||||
* close idle connections after 30 minutes ([99f247b](https://github.com/uptrace/go-clickhouse/commit/99f247ba5e188995fe8ddb39a3c54764efb98245))
|
||||
* enable opentelemetry support in protocol ([76504b2](https://github.com/uptrace/go-clickhouse/commit/76504b27784c509a39885a00750fbfc1eee0d8cc))
|
||||
* initial commit ([092a2db](https://github.com/uptrace/go-clickhouse/commit/092a2dbf28ca070bd6d6cc3426ecbc1d9bc02c6e))
|
||||
* **migrate:** added option to only mark migration up/down as applied on success ([f559e06](https://github.com/uptrace/go-clickhouse/commit/f559e06009e8fc263fa79cf99f692522a71f61ff))
|
||||
|
||||
|
||||
|
||||
# [0.3.0](https://github.com/uptrace/go-clickhouse/compare/v0.2.9...v0.3.0) (2023-01-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move FINAL modifier to the right place ([#52](https://github.com/uptrace/go-clickhouse/issues/52)) ([31f2e73](https://github.com/uptrace/go-clickhouse/commit/31f2e731adfb00031ebd82bbb0f2dcfc9e9c5b69))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add queries to create/drop views ([cbdda72](https://github.com/uptrace/go-clickhouse/commit/cbdda720552afe9b72ba5fc716e2d6b5a73f56e6))
|
||||
|
||||
|
||||
|
||||
## [0.2.9](https://github.com/uptrace/go-clickhouse/compare/v0.2.8...v0.2.9) (2022-08-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **migrate:** upping was applying zero migrations ([f1d380c](https://github.com/uptrace/go-clickhouse/commit/f1d380c16590cc2055274c2dc9418792682a8378))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add bfloat16 support ([75cc666](https://github.com/uptrace/go-clickhouse/commit/75cc6664576884120b629f38a473135cbe5214bd))
|
||||
* add Raw ([07c1f88](https://github.com/uptrace/go-clickhouse/commit/07c1f88173bb056e476b56d8a35dc3e5cf00c596))
|
||||
* add WithAutoCreateDatabase option ([74e949e](https://github.com/uptrace/go-clickhouse/commit/74e949e01d00e10718d375b43c6f72269165a19d))
|
||||
* **chmigrate:** add WithReplicated option ([76433f0](https://github.com/uptrace/go-clickhouse/commit/76433f0158277aaa93fec681bbfca7af623baf8a))
|
||||
* **migrate:** added option to only mark migration up/down as applied on success ([0b4f7bf](https://github.com/uptrace/go-clickhouse/commit/0b4f7bf56588c1060375f094406fe530b7086dcf))
|
||||
|
||||
|
||||
|
||||
## [0.2.8](https://github.com/uptrace/go-clickhouse/compare/v0.2.7...v0.2.8) (2022-05-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* enable opentelemetry support in protocol ([fb79ac4](https://github.com/uptrace/go-clickhouse/commit/fb79ac4b753bbf6ea794acb1d86fd8d116cf539c))
|
||||
|
||||
|
||||
|
||||
## [0.2.7](https://github.com/uptrace/go-clickhouse/compare/v0.2.6...v0.2.7) (2022-05-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow disabling compression for benchmarks ([a0d867b](https://github.com/uptrace/go-clickhouse/commit/a0d867b5f4478ac4879e73e1c8bb7cf0a8565142))
|
||||
|
||||
|
||||
|
||||
## [0.2.6](https://github.com/uptrace/go-clickhouse/compare/v0.2.5...v0.2.6) (2022-04-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add proper Rows implementation and some optimizations ([aca5cfe](https://github.com/uptrace/go-clickhouse/commit/aca5cfeb91514cf6dccb4ebc261755940b290449))
|
||||
* add support for DateTime64 ([1281505](https://github.com/uptrace/go-clickhouse/commit/1281505a77f39e0ff3203eddd969fded776e72f0))
|
||||
|
||||
|
||||
|
||||
#### 0.2.6 (2022-03-29)
|
||||
|
||||
# [](https://github.com/uptrace/go-clickhouse/compare/v0.2.4...v) (2022-03-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* change rollback to always record migrations ([d6e6e55](https://github.com/uptrace/go-clickhouse/commit/d6e6e55142d6cb369d838357a0700dd1becd50a8))
|
||||
* continue working with non UTC timezone ([d003d44](https://github.com/uptrace/go-clickhouse/commit/d003d44e55049b612610d48607809fe3fff5f151))
|
||||
|
||||
|
||||
|
||||
# [](https://github.com/uptrace/go-clickhouse/compare/v0.2.3...v) (2022-03-23)
|
||||
|
||||
|
||||
|
||||
# [](https://github.com/uptrace/go-clickhouse/compare/v0.2.2...v) (2022-03-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* close idle connections after 30 minutes ([844981b](https://github.com/uptrace/go-clickhouse/commit/844981bf1a831ab476e8854d413d2ea31c087d42))
|
||||
|
||||
|
||||
|
||||
# [](https://github.com/uptrace/go-clickhouse/compare/v0.2.1...v) (2022-03-21)
|
||||
|
||||
|
||||
|
||||
# [](https://github.com/uptrace/go-clickhouse/compare/v0.2.0...v) (2022-03-21)
|
||||
|
||||
|
||||
|
||||
# (2022-03-21)
|
||||
|
||||
|
||||
|
13
Makefile
13
Makefile
@@ -9,14 +9,25 @@ test:
|
||||
go vet); \
|
||||
done
|
||||
|
||||
.PHONY: go_mod_tidy
|
||||
go_mod_tidy:
|
||||
set -e; for dir in $(ALL_GO_MOD_DIRS); do \
|
||||
echo "go mod tidy in $${dir}"; \
|
||||
(cd "$${dir}" && go mod tidy -go=1.18); \
|
||||
done
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
set -e; for dir in $(ALL_GO_MOD_DIRS); do \
|
||||
echo "go get -u ./... && go mod tidy in $${dir}"; \
|
||||
(cd "$${dir}" && \
|
||||
go get -u ./... && \
|
||||
go mod tidy); \
|
||||
go mod tidy -go=1.18); \
|
||||
done
|
||||
|
||||
fmt:
|
||||
gofmt -w -s ./
|
||||
goimports -w -local github.com/uptrace/go-clickhouse ./
|
||||
|
||||
codegen:
|
||||
go run ./ch/internal/codegen/ -dir=ch/chschema
|
||||
|
48
README.md
48
README.md
@@ -5,26 +5,24 @@
|
||||
[](https://clickhouse.uptrace.dev/)
|
||||
[](https://discord.gg/rWtp5Aj)
|
||||
|
||||
This client uses native protocol to communicate with ClickHouse server and requires Go 1.18+ in
|
||||
order to use generics. This is not a database/sql driver, but the API is compatible.
|
||||
This ClickHouse client uses native protocol to communicate with ClickHouse server and requires Go
|
||||
1.18+ in order to use generics. This is not a database/sql driver, but the API is compatible.
|
||||
|
||||
Main features are:
|
||||
|
||||
- ClickHouse native protocol support and efficient column-oriented design.
|
||||
- API compatible with database/sql.
|
||||
- [Bun](https://github.com/uptrace/bun/)-like query builder.
|
||||
- [Selecting](https://clickhouse.uptrace.dev/guide/query-select.html) into scalars, structs, maps,
|
||||
slices of maps/structs/scalars.
|
||||
- [Selecting](https://clickhouse.uptrace.dev/guide/clickhouse-select.html) into scalars, structs,
|
||||
maps, slices of maps/structs/scalars.
|
||||
- `Date`, `DateTime`, and `DateTime64`.
|
||||
- `Array(T)` including nested arrays.
|
||||
- Enums and `LowCardinality(String)`.
|
||||
- `Nullable(T)` except `Nullable(Array(T))`.
|
||||
- [Migrations](https://clickhouse.uptrace.dev/guide/migrations.html).
|
||||
- [OpenTelemetry](https://clickhouse.uptrace.dev/guide/monitoring.html) support.
|
||||
- In production at [Uptrace](https://uptrace.dev/)
|
||||
|
||||
Unsupported:
|
||||
|
||||
- Server timezones other than UTC.
|
||||
- [Migrations](https://clickhouse.uptrace.dev/guide/clickhouse-migrations.html).
|
||||
- [OpenTelemetry](https://clickhouse.uptrace.dev/guide/clickhouse-monitoring-performance.html)
|
||||
support.
|
||||
- In production at [Uptrace](https://github.com/uptrace/uptrace)
|
||||
|
||||
Resources:
|
||||
|
||||
@@ -39,17 +37,23 @@ Resources:
|
||||
|
||||
**Read** (best of 3 runs):
|
||||
|
||||
| Library | Timing |
|
||||
| ---------------------------------------------------------------------------------------------------------------- | ------ |
|
||||
| [This library](example/benchmark/read-native/main.go) | 655ms |
|
||||
| [ClickHouse/clickhouse-go](https://github.com/ClickHouse/clickhouse-go/blob/v2/benchmark/v2/read-native/main.go) | 849ms |
|
||||
| Library | Timing |
|
||||
| ------------------------------------------------------------------------------------------------------------------ | ------ |
|
||||
| [This library](example/benchmark/read-native/main.go) | 655ms |
|
||||
| [ClickHouse/clickhouse-go](https://github.com/ClickHouse/clickhouse-go/blob/main/benchmark/v2/read-native/main.go) | 849ms |
|
||||
|
||||
**Write** (best of 3 runs):
|
||||
|
||||
| Library | Timing |
|
||||
| -------------------------------------------------------------------------------------------------------------------------- | ------ |
|
||||
| [This library](example/benchmark/write-native-columnar/main.go) | 475ms |
|
||||
| [ClickHouse/clickhouse-go](https://github.com/ClickHouse/clickhouse-go/blob/v2/benchmark/v2/write-native-columnar/main.go) | 881ms |
|
||||
| Library | Timing |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------- | ------ |
|
||||
| [This library](example/benchmark/write-native-columnar/main.go) | 475ms |
|
||||
| [ClickHouse/clickhouse-go](https://github.com/ClickHouse/clickhouse-go/blob/main/benchmark/v2/write-native-columnar/main.go) | 881ms |
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
go get github.com/uptrace/go-clickhouse@latest
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
@@ -107,3 +111,9 @@ func main() {
|
||||
fmt.Println(dest)
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [Golang ORM](https://github.com/uptrace/bun) for PostgreSQL, MySQL, MSSQL, and SQLite
|
||||
- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/)
|
||||
- [Golang HTTP router](https://github.com/uptrace/bunrouter)
|
||||
|
29
ch/bench_test.go
Normal file
29
ch/bench_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package ch_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func BenchmarkNumbers(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
db := chDB()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.QueryContext(ctx, "SELECT number FROM system.numbers_mt LIMIT 1000000")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
var count int
|
||||
for rows.Next() {
|
||||
count++
|
||||
}
|
||||
require.Equal(b, 1000000, count)
|
||||
}
|
||||
}
|
23
ch/bfloat16/bfloat16.go
Normal file
23
ch/bfloat16/bfloat16.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package bfloat16
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type T uint16
|
||||
|
||||
func From(f float64) T {
|
||||
return From32(float32(f))
|
||||
}
|
||||
|
||||
func From32(f float32) T {
|
||||
return T(math.Float32bits(f) >> 16)
|
||||
}
|
||||
|
||||
func (f T) Float32() float32 {
|
||||
return math.Float32frombits(uint32(f) << 16)
|
||||
}
|
||||
|
||||
func (f T) Float64() float64 {
|
||||
return float64(f.Float32())
|
||||
}
|
90
ch/ch.go
90
ch/ch.go
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
type (
|
||||
Safe = chschema.Safe
|
||||
Name = chschema.Name
|
||||
Ident = chschema.Ident
|
||||
CHModel = chschema.CHModel
|
||||
AfterScanRowHook = chschema.AfterScanRowHook
|
||||
@@ -70,34 +71,89 @@ func isBadConn(err error, allowTimeout bool) bool {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type ListValues struct {
|
||||
slice any
|
||||
}
|
||||
|
||||
var _ chschema.QueryAppender = ListValues{}
|
||||
|
||||
func List(slice any) ListValues {
|
||||
return ListValues{
|
||||
slice: slice,
|
||||
}
|
||||
}
|
||||
|
||||
func (in ListValues) AppendQuery(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
v := reflect.ValueOf(in.slice)
|
||||
if v.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("ch: In(non-slice %T)", in.slice)
|
||||
}
|
||||
|
||||
b = appendList(fmter, b, v)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type InValues struct {
|
||||
slice reflect.Value
|
||||
err error
|
||||
slice any
|
||||
}
|
||||
|
||||
var _ chschema.QueryAppender = InValues{}
|
||||
|
||||
func In(slice any) InValues {
|
||||
v := reflect.ValueOf(slice)
|
||||
if v.Kind() != reflect.Slice {
|
||||
return InValues{
|
||||
err: fmt.Errorf("ch: In(non-slice %T)", slice),
|
||||
}
|
||||
}
|
||||
return InValues{
|
||||
slice: v,
|
||||
slice: slice,
|
||||
}
|
||||
}
|
||||
|
||||
func (in InValues) AppendQuery(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
if in.err != nil {
|
||||
return nil, in.err
|
||||
v := reflect.ValueOf(in.slice)
|
||||
if v.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("ch: In(non-slice %T)", in.slice)
|
||||
}
|
||||
return appendIn(fmter, b, in.slice), nil
|
||||
|
||||
b = append(b, '(')
|
||||
b = appendList(fmter, b, v)
|
||||
b = append(b, ')')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func appendIn(fmter chschema.Formatter, b []byte, slice reflect.Value) []byte {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type ArrayValues struct {
|
||||
slice any
|
||||
}
|
||||
|
||||
var _ chschema.QueryAppender = ArrayValues{}
|
||||
|
||||
func Array(slice any) ArrayValues {
|
||||
return ArrayValues{
|
||||
slice: slice,
|
||||
}
|
||||
}
|
||||
|
||||
func (in ArrayValues) AppendQuery(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
v := reflect.ValueOf(in.slice)
|
||||
if v.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("ch: Array(non-slice %T)", in.slice)
|
||||
}
|
||||
|
||||
b = append(b, '[')
|
||||
b = appendList(fmter, b, v)
|
||||
b = append(b, ']')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func appendList(fmter chschema.Formatter, b []byte, slice reflect.Value) []byte {
|
||||
sliceLen := slice.Len()
|
||||
|
||||
if sliceLen == 0 {
|
||||
return append(b, "NULL"...)
|
||||
}
|
||||
|
||||
for i := 0; i < sliceLen; i++ {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
@@ -108,13 +164,7 @@ func appendIn(fmter chschema.Formatter, b []byte, slice reflect.Value) []byte {
|
||||
elem = elem.Elem()
|
||||
}
|
||||
|
||||
if elem.Kind() == reflect.Slice {
|
||||
b = append(b, '(')
|
||||
b = appendIn(fmter, b, elem)
|
||||
b = append(b, ')')
|
||||
} else {
|
||||
b = chschema.AppendValue(fmter, b, elem)
|
||||
}
|
||||
b = chschema.AppendValue(fmter, b, elem)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ type Conn struct {
|
||||
|
||||
ServerInfo chproto.ServerInfo
|
||||
|
||||
pooled bool
|
||||
Inited bool
|
||||
createdAt time.Time
|
||||
usedAt int64 // atomic
|
||||
@@ -33,6 +32,7 @@ func NewConn(netConn net.Conn) *Conn {
|
||||
wr: chproto.NewWriter(netConn),
|
||||
createdAt: time.Now(),
|
||||
}
|
||||
cn.SetUsedAt(time.Now())
|
||||
return cn
|
||||
}
|
||||
|
||||
@@ -45,10 +45,19 @@ func (cn *Conn) SetUsedAt(tm time.Time) {
|
||||
atomic.StoreInt64(&cn.usedAt, tm.Unix())
|
||||
}
|
||||
|
||||
func (cn *Conn) LocalAddr() net.Addr {
|
||||
return cn.netConn.LocalAddr()
|
||||
}
|
||||
|
||||
func (cn *Conn) RemoteAddr() net.Addr {
|
||||
return cn.netConn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (cn *Conn) Reader(ctx context.Context, timeout time.Duration) *chproto.Reader {
|
||||
_ = cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout))
|
||||
return cn.rd
|
||||
}
|
||||
|
||||
func (cn *Conn) WithReader(
|
||||
ctx context.Context,
|
||||
timeout time.Duration,
|
||||
|
@@ -76,11 +76,11 @@ type Config struct {
|
||||
Dialer func(context.Context) (net.Conn, error)
|
||||
OnClose func(*Conn) error
|
||||
|
||||
PoolSize int
|
||||
PoolTimeout time.Duration
|
||||
MinIdleConns int
|
||||
MaxIdleConns int
|
||||
MaxConnAge time.Duration
|
||||
PoolSize int
|
||||
PoolTimeout time.Duration
|
||||
MaxIdleConns int
|
||||
ConnMaxIdleTime time.Duration
|
||||
ConnMaxLifetime time.Duration
|
||||
}
|
||||
|
||||
type ConnPool struct {
|
||||
@@ -100,9 +100,6 @@ type ConnPool struct {
|
||||
connsMu sync.Mutex
|
||||
conns []*Conn
|
||||
idleConns []*Conn
|
||||
|
||||
poolSize int
|
||||
idleConnsLen int
|
||||
}
|
||||
|
||||
var _ Pooler = (*ConnPool)(nil)
|
||||
@@ -116,70 +113,22 @@ func New(cfg *Config) *ConnPool {
|
||||
idleConns: make([]*Conn, 0, cfg.PoolSize),
|
||||
}
|
||||
|
||||
p.connsMu.Lock()
|
||||
p.checkMinIdleConns()
|
||||
p.connsMu.Unlock()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *ConnPool) checkMinIdleConns() {
|
||||
if p.cfg.MinIdleConns == 0 {
|
||||
return
|
||||
}
|
||||
for p.poolSize < p.cfg.PoolSize && p.idleConnsLen < p.cfg.MinIdleConns {
|
||||
p.poolSize++
|
||||
p.idleConnsLen++
|
||||
go func() {
|
||||
err := p.addIdleConn()
|
||||
if err != nil {
|
||||
p.connsMu.Lock()
|
||||
p.poolSize--
|
||||
p.idleConnsLen--
|
||||
p.connsMu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ConnPool) addIdleConn() error {
|
||||
cn, err := p.dialConn(context.TODO(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.connsMu.Lock()
|
||||
p.conns = append(p.conns, cn)
|
||||
p.idleConns = append(p.idleConns, cn)
|
||||
p.connsMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ConnPool) NewConn(c context.Context) (*Conn, error) {
|
||||
return p.newConn(c, false)
|
||||
}
|
||||
|
||||
func (p *ConnPool) newConn(c context.Context, pooled bool) (*Conn, error) {
|
||||
cn, err := p.dialConn(c, pooled)
|
||||
func (p *ConnPool) NewConn(ctx context.Context) (*Conn, error) {
|
||||
cn, err := p.dialConn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.connsMu.Lock()
|
||||
p.conns = append(p.conns, cn)
|
||||
if pooled {
|
||||
// If pool is full remove the cn on next Put.
|
||||
if p.poolSize >= p.cfg.PoolSize {
|
||||
cn.pooled = false
|
||||
} else {
|
||||
p.poolSize++
|
||||
}
|
||||
}
|
||||
p.connsMu.Unlock()
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
func (p *ConnPool) dialConn(c context.Context, pooled bool) (*Conn, error) {
|
||||
func (p *ConnPool) dialConn(ctx context.Context) (*Conn, error) {
|
||||
if p.closed() {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
@@ -188,7 +137,7 @@ func (p *ConnPool) dialConn(c context.Context, pooled bool) (*Conn, error) {
|
||||
return nil, p.getLastDialError()
|
||||
}
|
||||
|
||||
netConn, err := p.cfg.Dialer(c)
|
||||
netConn, err := p.cfg.Dialer(ctx)
|
||||
if err != nil {
|
||||
p.setLastDialError(err)
|
||||
if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.cfg.PoolSize) {
|
||||
@@ -198,7 +147,6 @@ func (p *ConnPool) dialConn(c context.Context, pooled bool) (*Conn, error) {
|
||||
}
|
||||
|
||||
cn := NewConn(netConn)
|
||||
cn.pooled = pooled
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
@@ -254,7 +202,7 @@ func (p *ConnPool) Get(ctx context.Context) (*Conn, error) {
|
||||
break
|
||||
}
|
||||
|
||||
if p.cfg.MaxConnAge > 0 && time.Since(cn.createdAt) >= p.cfg.MaxConnAge {
|
||||
if !p.isHealthyConn(cn) {
|
||||
_ = p.CloseConn(cn)
|
||||
continue
|
||||
}
|
||||
@@ -265,7 +213,7 @@ func (p *ConnPool) Get(ctx context.Context) (*Conn, error) {
|
||||
|
||||
atomic.AddUint32(&p.stats.Misses, 1)
|
||||
|
||||
newcn, err := p.newConn(ctx, true)
|
||||
newcn, err := p.NewConn(ctx)
|
||||
if err != nil {
|
||||
p.freeTurn()
|
||||
return nil, err
|
||||
@@ -326,8 +274,6 @@ func (p *ConnPool) popIdle() *Conn {
|
||||
idx := len(p.idleConns) - 1
|
||||
cn := p.idleConns[idx]
|
||||
p.idleConns = p.idleConns[:idx]
|
||||
p.idleConnsLen--
|
||||
p.checkMinIdleConns()
|
||||
return cn
|
||||
}
|
||||
|
||||
@@ -338,29 +284,24 @@ func (p *ConnPool) Put(cn *Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
if !cn.pooled {
|
||||
p.Remove(cn, nil)
|
||||
return
|
||||
}
|
||||
|
||||
var atMaxCap bool
|
||||
var shouldCloseConn bool
|
||||
|
||||
p.connsMu.Lock()
|
||||
|
||||
if len(p.idleConns) < p.cfg.MaxIdleConns {
|
||||
if p.cfg.MaxIdleConns == 0 || len(p.idleConns) < p.cfg.MaxIdleConns {
|
||||
p.idleConns = append(p.idleConns, cn)
|
||||
p.idleConnsLen++
|
||||
} else {
|
||||
atMaxCap = true
|
||||
p.removeConn(cn)
|
||||
shouldCloseConn = true
|
||||
}
|
||||
|
||||
p.connsMu.Unlock()
|
||||
|
||||
if atMaxCap {
|
||||
p.Remove(cn, nil)
|
||||
}
|
||||
|
||||
p.freeTurn()
|
||||
|
||||
if shouldCloseConn {
|
||||
_ = p.closeConn(cn)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ConnPool) Remove(cn *Conn, reason error) {
|
||||
@@ -376,19 +317,15 @@ func (p *ConnPool) CloseConn(cn *Conn) error {
|
||||
|
||||
func (p *ConnPool) removeConnWithLock(cn *Conn) {
|
||||
p.connsMu.Lock()
|
||||
defer p.connsMu.Unlock()
|
||||
p.removeConn(cn)
|
||||
p.connsMu.Unlock()
|
||||
}
|
||||
|
||||
func (p *ConnPool) removeConn(cn *Conn) {
|
||||
for i, c := range p.conns {
|
||||
if c == cn {
|
||||
p.conns = append(p.conns[:i], p.conns[i+1:]...)
|
||||
if cn.pooled {
|
||||
p.poolSize--
|
||||
p.checkMinIdleConns()
|
||||
}
|
||||
return
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -411,20 +348,19 @@ func (p *ConnPool) Len() int {
|
||||
// IdleLen returns number of idle connections.
|
||||
func (p *ConnPool) IdleLen() int {
|
||||
p.connsMu.Lock()
|
||||
n := p.idleConnsLen
|
||||
n := len(p.idleConns)
|
||||
p.connsMu.Unlock()
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *ConnPool) Stats() *Stats {
|
||||
idleLen := p.IdleLen()
|
||||
return &Stats{
|
||||
Hits: atomic.LoadUint32(&p.stats.Hits),
|
||||
Misses: atomic.LoadUint32(&p.stats.Misses),
|
||||
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
|
||||
|
||||
TotalConns: uint32(p.Len()),
|
||||
IdleConns: uint32(idleLen),
|
||||
IdleConns: uint32(p.IdleLen()),
|
||||
StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
|
||||
}
|
||||
}
|
||||
@@ -446,10 +382,23 @@ func (p *ConnPool) Close() error {
|
||||
}
|
||||
}
|
||||
p.conns = nil
|
||||
p.poolSize = 0
|
||||
p.idleConns = nil
|
||||
p.idleConnsLen = 0
|
||||
p.connsMu.Unlock()
|
||||
|
||||
return firstErr
|
||||
}
|
||||
|
||||
func (p *ConnPool) isHealthyConn(cn *Conn) bool {
|
||||
now := time.Now()
|
||||
|
||||
if p.cfg.ConnMaxLifetime > 0 && now.Sub(cn.createdAt) >= p.cfg.ConnMaxLifetime {
|
||||
return false
|
||||
}
|
||||
if p.cfg.ConnMaxIdleTime > 0 && now.Sub(cn.UsedAt()) >= p.cfg.ConnMaxIdleTime {
|
||||
atomic.AddUint32(&p.stats.IdleConns, 1)
|
||||
return false
|
||||
}
|
||||
|
||||
cn.SetUsedAt(now)
|
||||
return true
|
||||
}
|
||||
|
@@ -17,8 +17,9 @@ type lz4Reader struct {
|
||||
|
||||
header []byte
|
||||
|
||||
data []byte
|
||||
pos int
|
||||
zdata []byte
|
||||
data []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func newLZ4Reader(r *bufio.Reader) *lz4Reader {
|
||||
@@ -29,16 +30,15 @@ func newLZ4Reader(r *bufio.Reader) *lz4Reader {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *lz4Reader) Init() {}
|
||||
|
||||
func (r *lz4Reader) Release() error {
|
||||
var err error
|
||||
if r.Buffered() > 0 {
|
||||
err = errUnreadData
|
||||
}
|
||||
|
||||
r.data = nil
|
||||
r.data = r.data[:0]
|
||||
r.pos = 0
|
||||
r.zdata = r.zdata[:0]
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -102,13 +102,13 @@ func (r *lz4Reader) readData() error {
|
||||
compressedSize := int(binary.LittleEndian.Uint32(r.header[17:])) - compressionHeaderSize
|
||||
uncompressedSize := int(binary.LittleEndian.Uint32(r.header[21:]))
|
||||
|
||||
zdata := make([]byte, compressedSize)
|
||||
r.zdata = grow(r.zdata, compressedSize)
|
||||
r.data = grow(r.data, uncompressedSize)
|
||||
|
||||
if _, err := io.ReadFull(r.rd, zdata); err != nil {
|
||||
if _, err := io.ReadFull(r.rd, r.zdata); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := lz4.UncompressBlock(zdata, r.data); err != nil {
|
||||
if _, err := lz4.UncompressBlock(r.zdata, r.data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package chproto
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
|
||||
"github.com/pierrec/lz4/v4"
|
||||
|
||||
@@ -25,50 +24,26 @@ const (
|
||||
blockSize = 1 << 20 // 1 MB
|
||||
)
|
||||
|
||||
type writeBuffer struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
var writeBufferPool = sync.Pool{
|
||||
New: func() any {
|
||||
return &writeBuffer{
|
||||
buf: make([]byte, blockSize),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func getWriterBuffer() *writeBuffer {
|
||||
return writeBufferPool.Get().(*writeBuffer)
|
||||
}
|
||||
|
||||
func putWriterBuffer(db *writeBuffer) {
|
||||
writeBufferPool.Put(db)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type lz4Writer struct {
|
||||
wr *bufio.Writer
|
||||
|
||||
data *writeBuffer
|
||||
pos int
|
||||
data []byte
|
||||
pos int
|
||||
zdata []byte
|
||||
}
|
||||
|
||||
func newLZ4Writer(w *bufio.Writer) *lz4Writer {
|
||||
return &lz4Writer{
|
||||
wr: w,
|
||||
wr: w,
|
||||
data: make([]byte, blockSize),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *lz4Writer) Init() {
|
||||
w.data = getWriterBuffer()
|
||||
w.pos = 0
|
||||
}
|
||||
|
||||
func (w *lz4Writer) Close() error {
|
||||
err := w.flush()
|
||||
putWriterBuffer(w.data)
|
||||
w.data = nil
|
||||
w.pos = 0
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -77,7 +52,7 @@ func (w *lz4Writer) Flush() error {
|
||||
}
|
||||
|
||||
func (w *lz4Writer) WriteByte(c byte) error {
|
||||
w.data.buf[w.pos] = c
|
||||
w.data[w.pos] = c
|
||||
w.pos++
|
||||
return w.checkFlush()
|
||||
}
|
||||
@@ -89,7 +64,7 @@ func (w *lz4Writer) WriteString(s string) (int, error) {
|
||||
func (w *lz4Writer) Write(data []byte) (int, error) {
|
||||
var written int
|
||||
for len(data) > 0 {
|
||||
n := copy(w.data.buf[w.pos:], data)
|
||||
n := copy(w.data[w.pos:], data)
|
||||
data = data[n:]
|
||||
w.pos += n
|
||||
if err := w.checkFlush(); err != nil {
|
||||
@@ -101,7 +76,7 @@ func (w *lz4Writer) Write(data []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (w *lz4Writer) checkFlush() error {
|
||||
if w.pos < len(w.data.buf) {
|
||||
if w.pos < len(w.data) {
|
||||
return nil
|
||||
}
|
||||
return w.flush()
|
||||
@@ -113,23 +88,23 @@ func (w *lz4Writer) flush() error {
|
||||
}
|
||||
|
||||
zlen := headerSize + lz4.CompressBlockBound(w.pos)
|
||||
zdata := make([]byte, zlen)
|
||||
w.zdata = grow(w.zdata, zlen)
|
||||
|
||||
compressedSize, err := compress(zdata[headerSize:], w.data.buf[:w.pos])
|
||||
compressedSize, err := compress(w.zdata[headerSize:], w.data[:w.pos])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
compressedSize += compressionHeaderSize
|
||||
|
||||
zdata[16] = lz4Compression
|
||||
binary.LittleEndian.PutUint32(zdata[17:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint32(zdata[21:], uint32(w.pos))
|
||||
w.zdata[16] = lz4Compression
|
||||
binary.LittleEndian.PutUint32(w.zdata[17:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint32(w.zdata[21:], uint32(w.pos))
|
||||
|
||||
checkSum := cityhash102.CityHash128(zdata[16:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint64(zdata[0:], checkSum.Lower64())
|
||||
binary.LittleEndian.PutUint64(zdata[8:], checkSum.Higher64())
|
||||
checkSum := cityhash102.CityHash128(w.zdata[16:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint64(w.zdata[0:], checkSum.Lower64())
|
||||
binary.LittleEndian.PutUint64(w.zdata[8:], checkSum.Higher64())
|
||||
|
||||
w.wr.Write(zdata[:checksumSize+compressedSize])
|
||||
w.wr.Write(w.zdata[:checksumSize+compressedSize])
|
||||
w.pos = 0
|
||||
|
||||
return nil
|
||||
|
@@ -11,23 +11,22 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
CompressionDisabled = 0
|
||||
CompressionEnabled = 1
|
||||
)
|
||||
|
||||
const (
|
||||
ServerHello = 0
|
||||
ServerData = 1
|
||||
ServerException = 2
|
||||
ServerProgress = 3
|
||||
ServerPong = 4
|
||||
ServerEndOfStream = 5
|
||||
ServerProfileInfo = 6
|
||||
ServerTotals = 7
|
||||
ServerExtremes = 8
|
||||
ServerTablesStatus = 9
|
||||
ServerLog = 10
|
||||
ServerTableColumns = 11
|
||||
ServerHello = 0
|
||||
ServerData = 1
|
||||
ServerException = 2
|
||||
ServerProgress = 3
|
||||
ServerPong = 4
|
||||
ServerEndOfStream = 5
|
||||
ServerProfileInfo = 6
|
||||
ServerTotals = 7
|
||||
ServerExtremes = 8
|
||||
ServerTablesStatus = 9
|
||||
ServerLog = 10
|
||||
ServerTableColumns = 11
|
||||
ServerPartUUIDs = 12
|
||||
ServerReadTaskRequest = 13
|
||||
ServerProfileEvents = 14
|
||||
ServerTreeReadTaskRequest = 15
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,3 +34,21 @@ const (
|
||||
QueryInitial = 1
|
||||
QuerySecondary = 2
|
||||
)
|
||||
|
||||
// see https://github.com/ClickHouse/ClickHouse/blob/master/src/Core/Protocol.h
|
||||
const (
|
||||
DBMS_MIN_REVISION_WITH_CLIENT_INFO = 54032
|
||||
DBMS_MIN_REVISION_WITH_SERVER_TIMEZONE = 54058
|
||||
DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO = 54060
|
||||
DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME = 54372
|
||||
DBMS_MIN_REVISION_WITH_VERSION_PATCH = 54401
|
||||
DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO = 54420
|
||||
DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS = 54429
|
||||
DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET = 54441
|
||||
DBMS_MIN_REVISION_WITH_OPENTELEMETRY = 54442
|
||||
DBMS_MIN_PROTOCOL_VERSION_WITH_DISTRIBUTED_DEPTH = 54448
|
||||
DBMS_MIN_PROTOCOL_VERSION_WITH_INITIAL_QUERY_START_TIME = 54449
|
||||
DBMS_MIN_PROTOCOL_VERSION_WITH_INCREMENTAL_PROFILE_EVENTS = 54451
|
||||
DBMS_MIN_REVISION_WITH_PARALLEL_REPLICAS = 54453
|
||||
DBMS_TCP_PROTOCOL_VERSION = DBMS_MIN_REVISION_WITH_PARALLEL_REPLICAS
|
||||
)
|
||||
|
@@ -36,15 +36,18 @@ func NewReader(r io.Reader) *Reader {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reader) WithCompression(fn func() error) error {
|
||||
r.zr.Init()
|
||||
r.rd = r.zr
|
||||
func (r *Reader) WithCompression(enabled bool, fn func() error) error {
|
||||
if enabled {
|
||||
r.rd = r.zr
|
||||
}
|
||||
|
||||
firstErr := fn()
|
||||
|
||||
r.rd = r.br
|
||||
if err := r.zr.Release(); err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
if enabled {
|
||||
r.rd = r.br
|
||||
if err := r.zr.Release(); err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
}
|
||||
}
|
||||
|
||||
return firstErr
|
||||
@@ -70,7 +73,7 @@ func (r *Reader) Uvarint() (uint64, error) {
|
||||
return binary.ReadUvarint(r.rd)
|
||||
}
|
||||
|
||||
func (r *Reader) Uint8() (uint8, error) {
|
||||
func (r *Reader) UInt8() (uint8, error) {
|
||||
c, err := r.rd.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -78,7 +81,7 @@ func (r *Reader) Uint8() (uint8, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (r *Reader) Uint16() (uint16, error) {
|
||||
func (r *Reader) UInt16() (uint16, error) {
|
||||
b, err := r.readNTemp(2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -86,7 +89,7 @@ func (r *Reader) Uint16() (uint16, error) {
|
||||
return binary.LittleEndian.Uint16(b), nil
|
||||
}
|
||||
|
||||
func (r *Reader) Uint32() (uint32, error) {
|
||||
func (r *Reader) UInt32() (uint32, error) {
|
||||
b, err := r.readNTemp(4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -94,7 +97,7 @@ func (r *Reader) Uint32() (uint32, error) {
|
||||
return binary.LittleEndian.Uint32(b), nil
|
||||
}
|
||||
|
||||
func (r *Reader) Uint64() (uint64, error) {
|
||||
func (r *Reader) UInt64() (uint64, error) {
|
||||
b, err := r.readNTemp(8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -103,27 +106,27 @@ func (r *Reader) Uint64() (uint64, error) {
|
||||
}
|
||||
|
||||
func (r *Reader) Int8() (int8, error) {
|
||||
num, err := r.Uint8()
|
||||
num, err := r.UInt8()
|
||||
return int8(num), err
|
||||
}
|
||||
|
||||
func (r *Reader) Int16() (int16, error) {
|
||||
num, err := r.Uint16()
|
||||
num, err := r.UInt16()
|
||||
return int16(num), err
|
||||
}
|
||||
|
||||
func (r *Reader) Int32() (int32, error) {
|
||||
num, err := r.Uint32()
|
||||
num, err := r.UInt32()
|
||||
return int32(num), err
|
||||
}
|
||||
|
||||
func (r *Reader) Int64() (int64, error) {
|
||||
num, err := r.Uint64()
|
||||
num, err := r.UInt64()
|
||||
return int64(num), err
|
||||
}
|
||||
|
||||
func (r *Reader) Float32() (float32, error) {
|
||||
num, err := r.Uint32()
|
||||
num, err := r.UInt32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -131,7 +134,7 @@ func (r *Reader) Float32() (float32, error) {
|
||||
}
|
||||
|
||||
func (r *Reader) Float64() (float64, error) {
|
||||
num, err := r.Uint64()
|
||||
num, err := r.UInt64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -180,7 +183,7 @@ func (r *Reader) readNTemp(n int) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (r *Reader) DateTime() (time.Time, error) {
|
||||
sec, err := r.Uint32()
|
||||
sec, err := r.UInt32()
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
@@ -191,7 +194,7 @@ func (r *Reader) DateTime() (time.Time, error) {
|
||||
}
|
||||
|
||||
func (r *Reader) Date() (time.Time, error) {
|
||||
days, err := r.Uint16()
|
||||
days, err := r.UInt16()
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
@@ -1,9 +1,5 @@
|
||||
package chproto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ServerInfo struct {
|
||||
Name string
|
||||
MinorVersion uint64
|
||||
@@ -25,19 +21,20 @@ func (srv *ServerInfo) ReadFrom(rd *Reader) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
timezone, err := rd.String()
|
||||
if err != nil {
|
||||
return err
|
||||
if srv.Revision >= DBMS_MIN_REVISION_WITH_SERVER_TIMEZONE {
|
||||
if _, err := rd.String(); err != nil { // timezone
|
||||
return err
|
||||
}
|
||||
}
|
||||
if timezone != "UTC" {
|
||||
return fmt.Errorf("ch: ClickHouse server uses timezone=%q, expected UTC", timezone)
|
||||
if srv.Revision >= DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME {
|
||||
if _, err := rd.String(); err != nil { // display name
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = rd.String(); err != nil { // display name
|
||||
return err
|
||||
}
|
||||
if _, err = rd.Uvarint(); err != nil { // server version patch
|
||||
return err
|
||||
if srv.Revision >= DBMS_MIN_REVISION_WITH_VERSION_PATCH {
|
||||
if _, err := rd.Uvarint(); err != nil { // server version patch
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -10,7 +10,10 @@ import (
|
||||
"github.com/uptrace/go-clickhouse/ch/internal"
|
||||
)
|
||||
|
||||
const uuidLen = 16
|
||||
const (
|
||||
uuidLen = 16
|
||||
secsInDay = 24 * 3600
|
||||
)
|
||||
|
||||
type writer interface {
|
||||
io.Writer
|
||||
@@ -39,20 +42,23 @@ func NewWriter(w io.Writer) *Writer {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Writer) WithCompression(fn func() error) {
|
||||
func (w *Writer) WithCompression(enabled bool, fn func() error) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
w.zw.Init()
|
||||
w.wr = w.zw
|
||||
if enabled {
|
||||
w.wr = w.zw
|
||||
}
|
||||
|
||||
w.err = fn()
|
||||
|
||||
if err := w.zw.Close(); err != nil && w.err == nil {
|
||||
w.err = err
|
||||
if enabled {
|
||||
if err := w.zw.Close(); err != nil && w.err == nil {
|
||||
w.err = err
|
||||
}
|
||||
w.wr = w.bw
|
||||
}
|
||||
w.wr = w.bw
|
||||
}
|
||||
|
||||
func (w *Writer) Flush() (err error) {
|
||||
@@ -73,7 +79,7 @@ func (w *Writer) Write(b []byte) {
|
||||
w.err = err
|
||||
}
|
||||
|
||||
func (w *Writer) writeByte(c byte) {
|
||||
func (w *Writer) WriteByte(c byte) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
@@ -85,7 +91,7 @@ func (w *Writer) Bool(flag bool) {
|
||||
if flag {
|
||||
num = 1
|
||||
}
|
||||
w.Uint8(num)
|
||||
w.UInt8(num)
|
||||
}
|
||||
|
||||
func (w *Writer) Uvarint(num uint64) {
|
||||
@@ -93,47 +99,47 @@ func (w *Writer) Uvarint(num uint64) {
|
||||
w.Write(w.buf[:n])
|
||||
}
|
||||
|
||||
func (w *Writer) Uint8(num uint8) {
|
||||
w.writeByte(num)
|
||||
func (w *Writer) UInt8(num uint8) {
|
||||
w.WriteByte(num)
|
||||
}
|
||||
|
||||
func (w *Writer) Uint16(num uint16) {
|
||||
func (w *Writer) UInt16(num uint16) {
|
||||
binary.LittleEndian.PutUint16(w.buf, num)
|
||||
w.Write(w.buf[:2])
|
||||
}
|
||||
|
||||
func (w *Writer) Uint32(num uint32) {
|
||||
func (w *Writer) UInt32(num uint32) {
|
||||
binary.LittleEndian.PutUint32(w.buf, num)
|
||||
w.Write(w.buf[:4])
|
||||
}
|
||||
|
||||
func (w *Writer) Uint64(num uint64) {
|
||||
func (w *Writer) UInt64(num uint64) {
|
||||
binary.LittleEndian.PutUint64(w.buf, num)
|
||||
w.Write(w.buf[:8])
|
||||
}
|
||||
|
||||
func (w *Writer) Int8(num int8) {
|
||||
w.Uint8(uint8(num))
|
||||
w.UInt8(uint8(num))
|
||||
}
|
||||
|
||||
func (w *Writer) Int16(num int16) {
|
||||
w.Uint16(uint16(num))
|
||||
w.UInt16(uint16(num))
|
||||
}
|
||||
|
||||
func (w *Writer) Int32(num int32) {
|
||||
w.Uint32(uint32(num))
|
||||
w.UInt32(uint32(num))
|
||||
}
|
||||
|
||||
func (w *Writer) Int64(num int64) {
|
||||
w.Uint64(uint64(num))
|
||||
w.UInt64(uint64(num))
|
||||
}
|
||||
|
||||
func (w *Writer) Float32(num float32) {
|
||||
w.Uint32(math.Float32bits(num))
|
||||
w.UInt32(math.Float32bits(num))
|
||||
}
|
||||
|
||||
func (w *Writer) Float64(num float64) {
|
||||
w.Uint64(math.Float64bits(num))
|
||||
w.UInt64(math.Float64bits(num))
|
||||
}
|
||||
|
||||
func (w *Writer) String(s string) {
|
||||
@@ -172,13 +178,11 @@ func packUUID(b []byte) []byte {
|
||||
}
|
||||
|
||||
func (w *Writer) DateTime(tm time.Time) {
|
||||
w.Uint32(uint32(unixTime(tm)))
|
||||
w.UInt32(uint32(unixTime(tm)))
|
||||
}
|
||||
|
||||
const secsInDay = 24 * 3600
|
||||
|
||||
func (w *Writer) Date(tm time.Time) {
|
||||
w.Uint16(uint16(unixTime(tm) / secsInDay))
|
||||
w.UInt16(uint16(unixTime(tm) / secsInDay))
|
||||
}
|
||||
|
||||
func unixTime(tm time.Time) int64 {
|
||||
|
@@ -106,7 +106,10 @@ func AppendString(b []byte, s string) []byte {
|
||||
}
|
||||
|
||||
func AppendTime(b []byte, tm time.Time) []byte {
|
||||
return tm.UTC().AppendFormat(b, "'2006-01-02 15:04:05'")
|
||||
b = append(b, "toDateTime('"...)
|
||||
b = tm.UTC().AppendFormat(b, "2006-01-02 15:04:05")
|
||||
b = append(b, "', 'UTC')"...)
|
||||
return b
|
||||
}
|
||||
|
||||
func AppendBytes(b []byte, bytes []byte) []byte {
|
||||
@@ -114,15 +117,12 @@ func AppendBytes(b []byte, bytes []byte) []byte {
|
||||
return AppendNull(b)
|
||||
}
|
||||
|
||||
b = append(b, '\'')
|
||||
|
||||
tmp := make([]byte, hex.EncodedLen(len(bytes)))
|
||||
hex.Encode(tmp, bytes)
|
||||
|
||||
b = append(b, "\\x"...)
|
||||
b = append(b, "unhex('"...)
|
||||
b = append(b, tmp...)
|
||||
|
||||
b = append(b, '\'')
|
||||
b = append(b, "')"...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
@@ -37,13 +37,13 @@ func (b *Block) Column(colName, colType string) *Column {
|
||||
|
||||
var col *Column
|
||||
if b.Table != nil {
|
||||
col = b.Table.NewColumn(colName, colType, b.NumRow)
|
||||
col = b.Table.NewColumn(colName, colType)
|
||||
}
|
||||
if col == nil {
|
||||
col = &Column{
|
||||
Name: colName,
|
||||
Type: colType,
|
||||
Columnar: NewColumnFromCHType(colType, b.NumRow),
|
||||
Columnar: NewColumn(colType, nil),
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,354 +0,0 @@
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
type ArrayColumnar interface {
|
||||
WriteOffset(wr *chproto.Writer, offset int) int
|
||||
WriteData(wr *chproto.Writer) error
|
||||
}
|
||||
|
||||
type ArrayLCStringColumn struct {
|
||||
*LCStringColumn
|
||||
}
|
||||
|
||||
func (c ArrayLCStringColumn) Type() reflect.Type {
|
||||
return stringSliceType
|
||||
}
|
||||
|
||||
func (c *ArrayLCStringColumn) WriteTo(wr *chproto.Writer) error {
|
||||
c.writeData(wr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayLCStringColumn) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
return c.readData(rd, numRow)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type ArrayColumn struct {
|
||||
Column reflect.Value
|
||||
|
||||
typ reflect.Type
|
||||
elem Columnar
|
||||
arrayElem ArrayColumnar
|
||||
}
|
||||
|
||||
var _ Columnar = (*ArrayColumn)(nil)
|
||||
|
||||
func NewArrayColumn(typ reflect.Type, chType string, numRow int) Columnar {
|
||||
elemType := chArrayElemType(chType)
|
||||
if elemType == "" {
|
||||
panic(fmt.Errorf("invalid array type: %q (Go type is %s)",
|
||||
chType, typ.String()))
|
||||
}
|
||||
|
||||
elem := NewColumn(typ.Elem(), elemType, 0)
|
||||
var arrayElem ArrayColumnar
|
||||
|
||||
if _, ok := elem.(*LCStringColumn); ok {
|
||||
panic("not reached")
|
||||
}
|
||||
arrayElem, _ = elem.(ArrayColumnar)
|
||||
|
||||
c := &ArrayColumn{
|
||||
typ: reflect.SliceOf(typ),
|
||||
elem: elem,
|
||||
arrayElem: arrayElem,
|
||||
}
|
||||
|
||||
c.Column = reflect.MakeSlice(c.typ, 0, numRow)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c ArrayColumn) Type() reflect.Type {
|
||||
return c.typ.Elem()
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) Reset(numRow int) {
|
||||
if c.Column.Cap() >= numRow {
|
||||
c.Column = c.Column.Slice(0, 0)
|
||||
} else {
|
||||
c.Column = reflect.MakeSlice(c.typ, 0, numRow)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) Set(v any) {
|
||||
c.Column = reflect.ValueOf(v)
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) Value() any {
|
||||
return c.Column.Interface()
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) Nullable(nulls Uint8Column) any {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) Len() int {
|
||||
return c.Column.Len()
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) Index(idx int) any {
|
||||
return c.Column.Index(idx).Interface()
|
||||
}
|
||||
|
||||
func (c ArrayColumn) Slice(s, e int) any {
|
||||
return c.Column.Slice(s, e).Interface()
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) ConvertAssign(idx int, v reflect.Value) error {
|
||||
v.Set(c.Column.Index(idx))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) AppendValue(v reflect.Value) {
|
||||
c.Column = reflect.Append(c.Column, v)
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if c.Column.Cap() >= numRow {
|
||||
c.Column = c.Column.Slice(0, numRow)
|
||||
} else {
|
||||
c.Column = reflect.MakeSlice(c.typ, numRow, numRow)
|
||||
}
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
offsets := make([]int, numRow)
|
||||
for i := 0; i < len(offsets); i++ {
|
||||
offset, err := rd.Uint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offsets[i] = int(offset)
|
||||
}
|
||||
|
||||
if err := c.elem.ReadFrom(rd, offsets[len(offsets)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var prev int
|
||||
for i, offset := range offsets {
|
||||
c.Column.Index(i).Set(reflect.ValueOf(c.elem.Slice(prev, offset)))
|
||||
prev = offset
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) WriteTo(wr *chproto.Writer) error {
|
||||
_ = c.WriteOffset(wr, 0)
|
||||
|
||||
colLen := c.Column.Len()
|
||||
for i := 0; i < colLen; i++ {
|
||||
// TODO: add SetValue or SetPointer
|
||||
c.elem.Set(c.Column.Index(i).Interface())
|
||||
|
||||
var err error
|
||||
if c.arrayElem != nil {
|
||||
err = c.arrayElem.WriteData(wr)
|
||||
} else {
|
||||
err = c.elem.WriteTo(wr)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayColumn) WriteOffset(wr *chproto.Writer, offset int) int {
|
||||
colLen := c.Column.Len()
|
||||
|
||||
for i := 0; i < colLen; i++ {
|
||||
el := c.Column.Index(i)
|
||||
offset += el.Len()
|
||||
wr.Uint64(uint64(offset))
|
||||
}
|
||||
|
||||
if c.arrayElem == nil {
|
||||
return offset
|
||||
}
|
||||
|
||||
offset = 0
|
||||
for i := 0; i < colLen; i++ {
|
||||
el := c.Column.Index(i)
|
||||
c.elem.Set(el.Interface()) // Use SetValue or SetPointer
|
||||
offset = c.arrayElem.WriteOffset(wr, offset)
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type StringArrayColumn struct {
|
||||
Column [][]string
|
||||
elem Columnar
|
||||
stringElem *StringColumn
|
||||
lcElem *LCStringColumn
|
||||
}
|
||||
|
||||
var _ Columnar = (*StringArrayColumn)(nil)
|
||||
|
||||
func NewStringArrayColumn(typ reflect.Type, chType string, numRow int) Columnar {
|
||||
if _, funcType := aggFuncNameAndType(chType); funcType != "" {
|
||||
chType = funcType
|
||||
}
|
||||
elemType := chArrayElemType(chType)
|
||||
if elemType == "" {
|
||||
panic(fmt.Errorf("invalid array type: %q (Go type is %s)",
|
||||
chType, typ.String()))
|
||||
}
|
||||
|
||||
columnar := NewColumn(typ.Elem(), elemType, 0)
|
||||
var stringElem *StringColumn
|
||||
var lcElem *LCStringColumn
|
||||
|
||||
switch v := columnar.(type) {
|
||||
case *StringColumn:
|
||||
stringElem = v
|
||||
case *LCStringColumn:
|
||||
stringElem = &v.StringColumn
|
||||
lcElem = v
|
||||
columnar = &ArrayLCStringColumn{v}
|
||||
case *EnumColumn:
|
||||
stringElem = &v.StringColumn
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported column: %T", v))
|
||||
}
|
||||
|
||||
return &StringArrayColumn{
|
||||
Column: make([][]string, 0, numRow),
|
||||
elem: columnar,
|
||||
stringElem: stringElem,
|
||||
lcElem: lcElem,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Reset(numRow int) {
|
||||
if cap(c.Column) >= numRow {
|
||||
c.Column = c.Column[:0]
|
||||
} else {
|
||||
c.Column = make([][]string, 0, numRow)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Type() reflect.Type {
|
||||
return stringSliceType
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Set(v any) {
|
||||
c.Column = v.([][]string)
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Value() any {
|
||||
return c.Column
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Nullable(nulls Uint8Column) any {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Len() int {
|
||||
return len(c.Column)
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) Index(idx int) any {
|
||||
return c.Column[idx]
|
||||
}
|
||||
|
||||
func (c StringArrayColumn) Slice(s, e int) any {
|
||||
return c.Column[s:e]
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) ConvertAssign(idx int, v reflect.Value) error {
|
||||
v.Set(reflect.ValueOf(c.Column[idx]))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) AppendValue(v reflect.Value) {
|
||||
c.Column = append(c.Column, v.Interface().([]string))
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cap(c.Column) >= numRow {
|
||||
c.Column = c.Column[:numRow]
|
||||
} else {
|
||||
c.Column = make([][]string, numRow)
|
||||
}
|
||||
|
||||
if c.lcElem != nil {
|
||||
if err := c.lcElem.readPrefix(rd, numRow); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
offsets := make([]int, numRow)
|
||||
|
||||
for i := 0; i < len(offsets); i++ {
|
||||
offset, err := rd.Uint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offsets[i] = int(offset)
|
||||
}
|
||||
|
||||
if err := c.elem.ReadFrom(rd, offsets[len(offsets)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var prev int
|
||||
for i, offset := range offsets {
|
||||
c.Column[i] = c.stringElem.Column[prev:offset]
|
||||
prev = offset
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) WriteTo(wr *chproto.Writer) error {
|
||||
if c.lcElem != nil {
|
||||
c.lcElem.writePrefix(wr)
|
||||
}
|
||||
|
||||
_ = c.WriteOffset(wr, 0)
|
||||
return c.WriteData(wr)
|
||||
}
|
||||
|
||||
var _ ArrayColumnar = (*StringArrayColumn)(nil)
|
||||
|
||||
func (c *StringArrayColumn) WriteOffset(wr *chproto.Writer, offset int) int {
|
||||
for _, el := range c.Column {
|
||||
offset += len(el)
|
||||
wr.Uint64(uint64(offset))
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
func (c *StringArrayColumn) WriteData(wr *chproto.Writer) error {
|
||||
for _, ss := range c.Column {
|
||||
c.stringElem.Column = ss
|
||||
if err := c.elem.WriteTo(wr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
3008
ch/chschema/column_gen.go
Normal file
3008
ch/chschema/column_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
319
ch/chschema/column_lowcard.go
Normal file
319
ch/chschema/column_lowcard.go
Normal file
@@ -0,0 +1,319 @@
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
type LCStringColumn struct {
|
||||
StringColumn
|
||||
}
|
||||
|
||||
var _ Columnar = (*LCStringColumn)(nil)
|
||||
|
||||
func NewLCStringColumn() Columnar {
|
||||
return new(LCStringColumn)
|
||||
}
|
||||
|
||||
func (c *LCStringColumn) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := c.readPrefix(rd, numRow); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.readData(rd, numRow)
|
||||
}
|
||||
|
||||
func (c *LCStringColumn) readPrefix(rd *chproto.Reader, numRow int) error {
|
||||
version, err := rd.Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if version != 1 {
|
||||
return fmt.Errorf("ch: got version=%d, wanted 1", version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *LCStringColumn) readData(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
flags, err := rd.Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lcKey := newLCKeyType(flags & 0xf)
|
||||
|
||||
dictSize, err := rd.UInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dict := make([]string, dictSize)
|
||||
|
||||
for i := range dict {
|
||||
s, err := rd.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dict[i] = s
|
||||
}
|
||||
|
||||
numKey, err := rd.UInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if int(numKey) != numRow {
|
||||
return fmt.Errorf("%d != %d", numKey, numRow)
|
||||
}
|
||||
|
||||
if cap(c.Column) >= int(numKey) {
|
||||
c.Column = c.Column[:numKey]
|
||||
} else {
|
||||
c.Column = make([]string, numKey)
|
||||
}
|
||||
|
||||
for i := 0; i < int(numKey); i++ {
|
||||
key, err := lcKey.read(rd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = dict[key]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *LCStringColumn) WriteTo(wr *chproto.Writer) error {
|
||||
c.writePrefix(wr)
|
||||
c.writeData(wr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *LCStringColumn) writePrefix(wr *chproto.Writer) {
|
||||
wr.Int64(1)
|
||||
}
|
||||
|
||||
func (c *LCStringColumn) writeData(wr *chproto.Writer) {
|
||||
if len(c.Column) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
keys := make([]int, len(c.Column))
|
||||
var lc lowCard
|
||||
|
||||
for i, s := range c.Column {
|
||||
keys[i] = lc.Add(s)
|
||||
}
|
||||
|
||||
const hasAdditionalKeys = 1 << 9
|
||||
const needUpdateDict = 1 << 10
|
||||
|
||||
dict := lc.Dict()
|
||||
lcKey := newLCKey(int64(len(dict)))
|
||||
|
||||
wr.Int64(int64(lcKey.typ) | hasAdditionalKeys | needUpdateDict)
|
||||
|
||||
wr.Int64(int64(len(dict)))
|
||||
for _, s := range dict {
|
||||
wr.String(s)
|
||||
}
|
||||
|
||||
wr.Int64(int64(len(keys)))
|
||||
for _, key := range keys {
|
||||
lcKey.write(wr, key)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type ArrayLCStringColumn struct {
|
||||
ArrayStringColumn
|
||||
lc LCStringColumn
|
||||
}
|
||||
|
||||
var _ Columnar = (*ArrayLCStringColumn)(nil)
|
||||
|
||||
func NewArrayLCStringColumn() Columnar {
|
||||
return new(ArrayLCStringColumn)
|
||||
}
|
||||
|
||||
func (c *ArrayLCStringColumn) ConvertAssign(idx int, dest reflect.Value) error {
|
||||
dest.Set(reflect.ValueOf(c.Column[idx]))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayLCStringColumn) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
if err := c.lc.readPrefix(rd, numRow); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offsets, err := c.readOffsets(rd, numRow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.lc.readData(rd, offsets[len(offsets)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var prev int
|
||||
for i, offset := range offsets {
|
||||
c.Column[i] = c.lc.Column[prev:offset]
|
||||
prev = offset
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayLCStringColumn) WriteTo(wr *chproto.Writer) error {
|
||||
c.lc.writePrefix(wr)
|
||||
_ = c.WriteOffset(wr, 0)
|
||||
return c.WriteData(wr)
|
||||
}
|
||||
|
||||
func (c *ArrayLCStringColumn) WriteData(wr *chproto.Writer) error {
|
||||
for _, ss := range c.Column {
|
||||
c.lc.Column = ss
|
||||
c.lc.writeData(wr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type lcKey struct {
|
||||
typ int8
|
||||
read func(*chproto.Reader) (int, error)
|
||||
write func(*chproto.Writer, int)
|
||||
}
|
||||
|
||||
func newLCKey(numKey int64) lcKey {
|
||||
if numKey <= math.MaxUint8 {
|
||||
return newLCKeyType(0)
|
||||
}
|
||||
if numKey <= math.MaxUint16 {
|
||||
return newLCKeyType(1)
|
||||
}
|
||||
if numKey <= math.MaxUint32 {
|
||||
return newLCKeyType(2)
|
||||
}
|
||||
return newLCKeyType(3)
|
||||
}
|
||||
|
||||
func newLCKeyType(typ int64) lcKey {
|
||||
switch typ {
|
||||
case 0:
|
||||
return lcKey{
|
||||
typ: 0,
|
||||
read: func(rd *chproto.Reader) (int, error) {
|
||||
n, err := rd.UInt8()
|
||||
return int(n), err
|
||||
},
|
||||
write: func(wr *chproto.Writer, n int) {
|
||||
wr.UInt8(uint8(n))
|
||||
},
|
||||
}
|
||||
case 1:
|
||||
return lcKey{
|
||||
typ: int8(1),
|
||||
read: func(rd *chproto.Reader) (int, error) {
|
||||
n, err := rd.UInt16()
|
||||
return int(n), err
|
||||
},
|
||||
write: func(wr *chproto.Writer, n int) {
|
||||
wr.UInt16(uint16(n))
|
||||
},
|
||||
}
|
||||
case 2:
|
||||
return lcKey{
|
||||
typ: 2,
|
||||
read: func(rd *chproto.Reader) (int, error) {
|
||||
n, err := rd.UInt32()
|
||||
return int(n), err
|
||||
},
|
||||
write: func(wr *chproto.Writer, n int) {
|
||||
wr.UInt32(uint32(n))
|
||||
},
|
||||
}
|
||||
case 3:
|
||||
return lcKey{
|
||||
typ: 3,
|
||||
read: func(rd *chproto.Reader) (int, error) {
|
||||
n, err := rd.UInt64()
|
||||
return int(n), err
|
||||
},
|
||||
write: func(wr *chproto.Writer, n int) {
|
||||
wr.UInt64(uint64(n))
|
||||
},
|
||||
}
|
||||
default:
|
||||
panic("not reached")
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type lowCard struct {
|
||||
slice sliceMap
|
||||
dict map[string]int
|
||||
}
|
||||
|
||||
func (lc *lowCard) Add(word string) int {
|
||||
if i, ok := lc.dict[word]; ok {
|
||||
return i
|
||||
}
|
||||
|
||||
if lc.dict == nil {
|
||||
lc.dict = make(map[string]int)
|
||||
}
|
||||
|
||||
i := lc.slice.Add(word)
|
||||
lc.dict[word] = i
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func (lc *lowCard) Dict() []string {
|
||||
return lc.slice.Slice()
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type sliceMap struct {
|
||||
ss []string
|
||||
}
|
||||
|
||||
func (m sliceMap) Len() int {
|
||||
return len(m.ss)
|
||||
}
|
||||
|
||||
func (m sliceMap) Get(word string) (int, bool) {
|
||||
for i, s := range m.ss {
|
||||
if s == word {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (m *sliceMap) Add(word string) int {
|
||||
m.ss = append(m.ss, word)
|
||||
return len(m.ss) - 1
|
||||
}
|
||||
|
||||
func (m sliceMap) Slice() []string {
|
||||
return m.ss
|
||||
}
|
@@ -7,21 +7,35 @@ import (
|
||||
)
|
||||
|
||||
type NullableColumn struct {
|
||||
Nulls Uint8Column
|
||||
Nulls UInt8Column
|
||||
Values Columnar
|
||||
nullable reflect.Value // reflect.Slice
|
||||
}
|
||||
|
||||
func NullableNewColumnFunc(fn NewColumnFunc) NewColumnFunc {
|
||||
return func(typ reflect.Type, chType string, numRow int) Columnar {
|
||||
func NewNullableColumnFunc(fn NewColumnFunc) NewColumnFunc {
|
||||
return func() Columnar {
|
||||
return &NullableColumn{
|
||||
Values: fn(typ, chType, numRow),
|
||||
Values: fn(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ Columnar = (*NullableColumn)(nil)
|
||||
|
||||
func (c *NullableColumn) Init(chType string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *NullableColumn) AllocForReading(numRow int) {
|
||||
c.Nulls.AllocForReading(numRow)
|
||||
c.Values.AllocForReading(numRow)
|
||||
}
|
||||
|
||||
func (c *NullableColumn) ResetForWriting(numRow int) {
|
||||
c.Nulls.ResetForWriting(numRow)
|
||||
c.Values.ResetForWriting(numRow)
|
||||
}
|
||||
|
||||
func (c *NullableColumn) Type() reflect.Type {
|
||||
return reflect.PtrTo(c.Values.Type())
|
||||
}
|
||||
@@ -44,7 +58,7 @@ func (c *NullableColumn) Value() any {
|
||||
return c.nullable.Interface()
|
||||
}
|
||||
|
||||
func (c *NullableColumn) Nullable(nulls Uint8Column) any {
|
||||
func (c *NullableColumn) Nullable(nulls UInt8Column) any {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
|
217
ch/chschema/column_safe_gen.go
Normal file
217
ch/chschema/column_safe_gen.go
Normal file
@@ -0,0 +1,217 @@
|
||||
//go:build !amd64 && !arm64
|
||||
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
func (c *Int8Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.Int8()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int8Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.Int8(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt8Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.UInt8()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt8Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.UInt8(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int16Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.Int16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int16Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.Int16(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt16Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.UInt16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt16Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.UInt16(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int32Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.Int32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int32Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.Int32(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt32Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.UInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt32Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.UInt32(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int64Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int64Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.Int64(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt64Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.UInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt64Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.UInt64(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Float32Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.Float32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Float32Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.Float32(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Float64Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.Float64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Float64Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.Float64(n)
|
||||
}
|
||||
return nil
|
||||
}
|
351
ch/chschema/column_unsafe_gen.go
Normal file
351
ch/chschema/column_unsafe_gen.go
Normal file
@@ -0,0 +1,351 @@
|
||||
//go:build amd64 || arm64
|
||||
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
func (c *Int8Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 8 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Int8Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 8 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt8Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 8 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *UInt8Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 8 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int16Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 16 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Int16Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 16 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt16Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 16 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *UInt16Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 16 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int32Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 32 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Int32Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 32 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt32Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 32 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *UInt32Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 32 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Int64Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 64 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Int64Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 64 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UInt64Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 64 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *UInt64Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 64 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Float32Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 32 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Float32Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 32 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Float64Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = 64 / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Float64Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = 64 / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
@@ -40,7 +40,7 @@ func parseEnum(s string) *enumInfo {
|
||||
}
|
||||
|
||||
func _parseEnum(chType string) (*enumInfo, error) {
|
||||
s := enumType(chType)
|
||||
s := chEnumType(chType)
|
||||
if s == "" {
|
||||
return nil, fmt.Errorf("can't parse enum type: %q", chType)
|
||||
}
|
||||
|
@@ -27,6 +27,10 @@ func NewFormatter() Formatter {
|
||||
return Formatter{}
|
||||
}
|
||||
|
||||
func (f Formatter) AppendName(b []byte, ident string) []byte {
|
||||
return AppendName(b, ident)
|
||||
}
|
||||
|
||||
func (f Formatter) AppendIdent(b []byte, ident string) []byte {
|
||||
return AppendIdent(b, ident)
|
||||
}
|
||||
|
@@ -1,53 +0,0 @@
|
||||
package chschema
|
||||
|
||||
type lowCard struct {
|
||||
slice sliceMap
|
||||
dict map[string]int
|
||||
}
|
||||
|
||||
func (lc *lowCard) Add(word string) int {
|
||||
if i, ok := lc.dict[word]; ok {
|
||||
return i
|
||||
}
|
||||
|
||||
if lc.dict == nil {
|
||||
lc.dict = make(map[string]int)
|
||||
}
|
||||
|
||||
i := lc.slice.Add(word)
|
||||
lc.dict[word] = i
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func (lc *lowCard) Dict() []string {
|
||||
return lc.slice.Slice()
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type sliceMap struct {
|
||||
ss []string
|
||||
}
|
||||
|
||||
func (m sliceMap) Len() int {
|
||||
return len(m.ss)
|
||||
}
|
||||
|
||||
func (m sliceMap) Get(word string) (int, bool) {
|
||||
for i, s := range m.ss {
|
||||
if s == word {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (m *sliceMap) Add(word string) int {
|
||||
m.ss = append(m.ss, word)
|
||||
return len(m.ss) - 1
|
||||
}
|
||||
|
||||
func (m sliceMap) Slice() []string {
|
||||
return m.ss
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/internal"
|
||||
@@ -27,20 +28,50 @@ func (s Safe) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// FQN represents a fully qualified SQL name, for example, table or column name.
|
||||
type FQN string
|
||||
// Name represents a SQL identifier, for example, table or column name.
|
||||
type Name string
|
||||
|
||||
var _ QueryAppender = (*FQN)(nil)
|
||||
var _ QueryAppender = (*Name)(nil)
|
||||
|
||||
func (s FQN) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
func (s Name) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
return fmter.AppendName(b, string(s)), nil
|
||||
}
|
||||
|
||||
func AppendName(b []byte, field string) []byte {
|
||||
return appendName(b, internal.Bytes(field))
|
||||
}
|
||||
|
||||
func appendName(b, src []byte) []byte {
|
||||
const quote = '"'
|
||||
|
||||
b = append(b, quote)
|
||||
for _, c := range src {
|
||||
if c == quote {
|
||||
b = append(b, quote, quote)
|
||||
} else {
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
b = append(b, quote)
|
||||
return b
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Ident represents a fully qualified SQL name, for example, table or column name.
|
||||
type Ident string
|
||||
|
||||
var _ QueryAppender = (*Name)(nil)
|
||||
|
||||
func (s Ident) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
return fmter.AppendIdent(b, string(s)), nil
|
||||
}
|
||||
|
||||
func AppendFQN(b []byte, field string) []byte {
|
||||
return appendFQN(b, internal.Bytes(field))
|
||||
func AppendIdent(b []byte, field string) []byte {
|
||||
return appendIdent(b, internal.Bytes(field))
|
||||
}
|
||||
|
||||
func appendFQN(b, src []byte) []byte {
|
||||
func appendIdent(b, src []byte) []byte {
|
||||
const quote = '"'
|
||||
|
||||
var quoted bool
|
||||
@@ -77,34 +108,6 @@ loop:
|
||||
return b
|
||||
}
|
||||
|
||||
// Ident represents a SQL identifier, for example, table or column name.
|
||||
type Ident string
|
||||
|
||||
var _ QueryAppender = (*Ident)(nil)
|
||||
|
||||
func (s Ident) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
return fmter.AppendIdent(b, string(s)), nil
|
||||
}
|
||||
|
||||
func AppendIdent(b []byte, field string) []byte {
|
||||
return appendIdent(b, internal.Bytes(field))
|
||||
}
|
||||
|
||||
func appendIdent(b, src []byte) []byte {
|
||||
const quote = '"'
|
||||
|
||||
b = append(b, quote)
|
||||
for _, c := range src {
|
||||
if c == quote {
|
||||
b = append(b, quote, quote)
|
||||
} else {
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
b = append(b, quote)
|
||||
return b
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type QueryWithArgs struct {
|
||||
@@ -126,7 +129,7 @@ func SafeQuery(query string, args []any) QueryWithArgs {
|
||||
}
|
||||
}
|
||||
|
||||
func UnsafeIdent(ident string) QueryWithArgs {
|
||||
func UnsafeName(ident string) QueryWithArgs {
|
||||
return QueryWithArgs{Query: ident}
|
||||
}
|
||||
|
||||
@@ -134,9 +137,13 @@ func (q QueryWithArgs) IsZero() bool {
|
||||
return q.Query == "" && q.Args == nil
|
||||
}
|
||||
|
||||
func (q QueryWithArgs) IsEmpty() bool {
|
||||
return q.Query == ""
|
||||
}
|
||||
|
||||
func (q QueryWithArgs) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
if q.Args == nil {
|
||||
return fmter.AppendIdent(b, q.Query), nil
|
||||
return fmter.AppendName(b, q.Query), nil
|
||||
}
|
||||
return fmter.AppendQuery(b, q.Query, q.Args...), nil
|
||||
}
|
||||
@@ -159,3 +166,43 @@ func SafeQueryWithSep(query string, args []any, sep string) QueryWithSep {
|
||||
Sep: sep,
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type ArrayValue struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func Array(vi interface{}) *ArrayValue {
|
||||
return &ArrayValue{
|
||||
v: reflect.ValueOf(vi),
|
||||
}
|
||||
}
|
||||
|
||||
var _ QueryAppender = (*ArrayValue)(nil)
|
||||
|
||||
func (a *ArrayValue) AppendQuery(fmter Formatter, b []byte) ([]byte, error) {
|
||||
if !a.v.IsValid() || a.v.Len() == 0 {
|
||||
b = append(b, "[]"...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
typ := a.v.Type()
|
||||
elemType := typ.Elem()
|
||||
appendElem := Appender(elemType)
|
||||
|
||||
b = append(b, '[')
|
||||
|
||||
ln := a.v.Len()
|
||||
for i := 0; i < ln; i++ {
|
||||
if i > 0 {
|
||||
b = append(b, ',')
|
||||
}
|
||||
elem := a.v.Index(i)
|
||||
b = appendElem(fmter, b, elem)
|
||||
}
|
||||
|
||||
b = append(b, ']')
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
@@ -13,8 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
discardUnknownColumnsFlag = internal.Flag(1) << iota
|
||||
columnarFlag
|
||||
columnarFlag = internal.Flag(1) << iota
|
||||
afterScanBlockHookFlag
|
||||
)
|
||||
|
||||
@@ -155,7 +154,7 @@ func (t *Table) addFields(typ reflect.Type, baseIndex []int) {
|
||||
}
|
||||
}
|
||||
if f.NewColumn == nil {
|
||||
f.NewColumn = ColumnFactory(f.Type, f.CHType)
|
||||
f.NewColumn = ColumnFactory(f.CHType, f.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,7 +211,7 @@ func (t *Table) newField(f reflect.StructField, index []int, tag tagparser.Tag)
|
||||
field.CHType = s
|
||||
field.setFlag(customTypeFlag)
|
||||
} else {
|
||||
field.CHType = clickhouseType(f.Type)
|
||||
field.CHType = chType(f.Type)
|
||||
}
|
||||
|
||||
if tag.HasOption("lc") {
|
||||
@@ -252,7 +251,7 @@ func (t *Table) addField(field *Field) {
|
||||
t.FieldMap[field.CHName] = field
|
||||
}
|
||||
|
||||
func (t *Table) NewColumn(colName, colType string, numRow int) *Column {
|
||||
func (t *Table) NewColumn(colName, colType string) *Column {
|
||||
field, ok := t.FieldMap[colName]
|
||||
if !ok {
|
||||
internal.Logger.Printf("ch: %s has no column=%q", t, colName)
|
||||
@@ -260,22 +259,20 @@ func (t *Table) NewColumn(colName, colType string, numRow int) *Column {
|
||||
}
|
||||
|
||||
if colType != field.CHType {
|
||||
if field.CHType != chtype.Any {
|
||||
internal.Logger.Printf("got column type %q, but %s.%s has type %q",
|
||||
colType, t.Type.Name(), field.GoName, field.CHType)
|
||||
}
|
||||
|
||||
return &Column{
|
||||
Name: colName,
|
||||
Type: colType,
|
||||
Columnar: ColumnFactory(field.Type, colType)(field.Type, colType, numRow),
|
||||
Columnar: NewColumn(colType, field.Type),
|
||||
}
|
||||
}
|
||||
|
||||
col := field.NewColumn()
|
||||
col.Init(field.CHType)
|
||||
|
||||
return &Column{
|
||||
Name: colName,
|
||||
Type: field.CHType,
|
||||
Columnar: field.NewColumn(field.Type, field.CHType, numRow),
|
||||
Columnar: col,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +288,7 @@ func (t *Table) AppendNamedArg(
|
||||
}
|
||||
|
||||
func quoteTableName(s string) Safe {
|
||||
return Safe(appendFQN(nil, internal.Bytes(s)))
|
||||
return Safe(appendIdent(nil, internal.Bytes(s)))
|
||||
}
|
||||
|
||||
func quoteColumnName(s string) Safe {
|
||||
|
@@ -4,15 +4,42 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/bfloat16"
|
||||
"github.com/uptrace/go-clickhouse/ch/chtype"
|
||||
"github.com/uptrace/go-clickhouse/ch/internal"
|
||||
)
|
||||
|
||||
var chType = [...]string{
|
||||
reflect.Bool: chtype.UInt8,
|
||||
var (
|
||||
boolType = reflect.TypeOf(false)
|
||||
int8Type = reflect.TypeOf(int8(0))
|
||||
int16Type = reflect.TypeOf(int16(0))
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uint8Type = reflect.TypeOf(uint8(0))
|
||||
uint16Type = reflect.TypeOf(uint16(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
|
||||
stringType = reflect.TypeOf("")
|
||||
bytesType = reflect.TypeOf((*[]byte)(nil)).Elem()
|
||||
uuidType = reflect.TypeOf((*UUID)(nil)).Elem()
|
||||
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
ipType = reflect.TypeOf((*net.IP)(nil)).Elem()
|
||||
ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem()
|
||||
bfloat16MapType = reflect.TypeOf((*map[bfloat16.T]uint64)(nil)).Elem()
|
||||
|
||||
sliceUint64Type = reflect.TypeOf((*[]uint64)(nil)).Elem()
|
||||
sliceFloat32Type = reflect.TypeOf((*[]float32)(nil)).Elem()
|
||||
)
|
||||
|
||||
var chTypes = [...]string{
|
||||
reflect.Bool: chtype.Bool,
|
||||
reflect.Int: chtype.Int64,
|
||||
reflect.Int8: chtype.Int8,
|
||||
reflect.Int16: chtype.Int16,
|
||||
@@ -40,8 +67,181 @@ var chType = [...]string{
|
||||
reflect.UnsafePointer: "",
|
||||
}
|
||||
|
||||
// keep in sync with ColumnFactory
|
||||
func clickhouseType(typ reflect.Type) string {
|
||||
type NewColumnFunc func() Columnar
|
||||
|
||||
func NewColumn(chType string, typ reflect.Type) Columnar {
|
||||
col := ColumnFactory(chType, typ)()
|
||||
col.Init(chType)
|
||||
return col
|
||||
}
|
||||
|
||||
func ColumnFactory(chType string, typ reflect.Type) NewColumnFunc {
|
||||
switch chType {
|
||||
case chtype.Int8:
|
||||
return NewInt8Column
|
||||
case chtype.Int16:
|
||||
return NewInt16Column
|
||||
case chtype.Int32:
|
||||
return NewInt32Column
|
||||
case chtype.Int64:
|
||||
return NewInt64Column
|
||||
case chtype.UInt8:
|
||||
return NewUInt8Column
|
||||
case chtype.UInt16:
|
||||
return NewUInt16Column
|
||||
case chtype.UInt32:
|
||||
return NewUInt32Column
|
||||
case chtype.UInt64:
|
||||
return NewUInt64Column
|
||||
case chtype.Float32:
|
||||
return NewFloat32Column
|
||||
case chtype.Float64:
|
||||
return NewFloat64Column
|
||||
|
||||
case chtype.String:
|
||||
if typ == bytesType {
|
||||
return NewBytesColumn
|
||||
}
|
||||
return NewStringColumn
|
||||
case "LowCardinality(String)":
|
||||
return NewLCStringColumn
|
||||
case chtype.Bool:
|
||||
return NewBoolColumn
|
||||
case chtype.UUID:
|
||||
return NewUUIDColumn
|
||||
case chtype.IPv6:
|
||||
return NewIPColumn
|
||||
|
||||
case chtype.DateTime:
|
||||
return NewDateTimeColumn
|
||||
case chtype.Date:
|
||||
return NewDateColumn
|
||||
|
||||
case "Array(Int8)":
|
||||
return NewArrayInt8Column
|
||||
case "Array(UInt8)":
|
||||
return NewArrayUInt8Column
|
||||
case "Array(Int16)":
|
||||
return NewArrayInt16Column
|
||||
case "Array(UInt16)":
|
||||
return NewArrayUInt16Column
|
||||
case "Array(Int32)":
|
||||
return NewArrayInt32Column
|
||||
case "Array(UInt32)":
|
||||
return NewArrayUInt32Column
|
||||
case "Array(Int64)":
|
||||
return NewArrayInt64Column
|
||||
case "Array(UInt64)":
|
||||
return NewArrayUInt64Column
|
||||
case "Array(Float32)":
|
||||
return NewArrayFloat32Column
|
||||
case "Array(Float64)":
|
||||
return NewArrayFloat64Column
|
||||
|
||||
case "Array(String)":
|
||||
return NewArrayStringColumn
|
||||
case "Array(LowCardinality(String))":
|
||||
return NewArrayLCStringColumn
|
||||
case "Array(DateTime)":
|
||||
return NewArrayDateTimeColumn
|
||||
case "Array(Bool)":
|
||||
return NewArrayBoolColumn
|
||||
|
||||
case "Array(Array(Int8))":
|
||||
return NewArrayArrayInt8Column
|
||||
case "Array(Array(UInt8))":
|
||||
return NewArrayArrayUInt8Column
|
||||
case "Array(Array(Int16))":
|
||||
return NewArrayArrayInt16Column
|
||||
case "Array(Array(UInt16))":
|
||||
return NewArrayArrayUInt16Column
|
||||
case "Array(Array(Int32))":
|
||||
return NewArrayArrayInt32Column
|
||||
case "Array(Array(UInt32))":
|
||||
return NewArrayArrayUInt32Column
|
||||
case "Array(Array(Int64))":
|
||||
return NewArrayArrayInt64Column
|
||||
case "Array(Array(UInt64))":
|
||||
return NewArrayArrayUInt64Column
|
||||
case "Array(Array(Float32))":
|
||||
return NewArrayArrayFloat32Column
|
||||
case "Array(Array(Float64))":
|
||||
return NewArrayArrayFloat64Column
|
||||
|
||||
case "Array(Array(String))":
|
||||
return NewArrayArrayStringColumn
|
||||
case "Array(Array(DateTime))":
|
||||
return NewArrayArrayDateTimeColumn
|
||||
case "Array(Array(Bool))":
|
||||
return NewArrayArrayStringColumn
|
||||
|
||||
case chtype.Any:
|
||||
return nil
|
||||
}
|
||||
|
||||
if chType := chEnumType(chType); chType != "" {
|
||||
return NewEnumColumn
|
||||
}
|
||||
if chType := chArrayElemType(chType); chType != "" {
|
||||
if chType := chEnumType(chType); chType != "" {
|
||||
return NewArrayEnumColumn
|
||||
}
|
||||
}
|
||||
if isDateTime64Type(chType) {
|
||||
return NewDateTime64Column
|
||||
}
|
||||
if chType := chDateTimeType(chType); chType != "" {
|
||||
return ColumnFactory(chType, typ)
|
||||
}
|
||||
if chType := chNullableType(chType); chType != "" {
|
||||
if typ != nil {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
return NewNullableColumnFunc(ColumnFactory(chType, typ))
|
||||
}
|
||||
|
||||
if chType := chSimpleAggFunc(chType); chType != "" {
|
||||
return ColumnFactory(chType, typ)
|
||||
}
|
||||
|
||||
if funcName, _ := aggFuncNameAndType(chType); funcName != "" {
|
||||
switch funcName {
|
||||
case "quantileBFloat16", "quantilesBFloat16":
|
||||
return NewBFloat16HistColumn
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported ClickHouse type: %s", chType))
|
||||
}
|
||||
}
|
||||
|
||||
if typ == nil {
|
||||
panic(fmt.Errorf("unsupported ClickHouse column: %s", chType))
|
||||
}
|
||||
|
||||
kind := typ.Kind()
|
||||
|
||||
switch kind {
|
||||
case reflect.Ptr:
|
||||
if typ.Elem().Kind() == reflect.Struct {
|
||||
return NewJSONColumn
|
||||
}
|
||||
return NewNullableColumnFunc(ColumnFactory(chNullableType(chType), typ.Elem()))
|
||||
case reflect.Slice:
|
||||
switch elem := typ.Elem(); elem.Kind() {
|
||||
case reflect.Ptr:
|
||||
if elem.Elem().Kind() == reflect.Struct {
|
||||
return NewJSONColumn
|
||||
}
|
||||
case reflect.Struct:
|
||||
if elem != timeType {
|
||||
return NewJSONColumn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("unsupported ClickHouse column: %s", chType))
|
||||
}
|
||||
|
||||
func chType(typ reflect.Type) string {
|
||||
switch typ {
|
||||
case timeType:
|
||||
return chtype.DateTime
|
||||
@@ -55,7 +255,7 @@ func clickhouseType(typ reflect.Type) string {
|
||||
if typ.Elem().Kind() == reflect.Struct {
|
||||
return chtype.String
|
||||
}
|
||||
return fmt.Sprintf("Nullable(%s)", clickhouseType(typ.Elem()))
|
||||
return fmt.Sprintf("Nullable(%s)", chType(typ.Elem()))
|
||||
case reflect.Slice:
|
||||
switch elem := typ.Elem(); elem.Kind() {
|
||||
case reflect.Ptr:
|
||||
@@ -70,265 +270,28 @@ func clickhouseType(typ reflect.Type) string {
|
||||
return chtype.String // []byte
|
||||
}
|
||||
|
||||
return "Array(" + clickhouseType(typ.Elem()) + ")"
|
||||
return "Array(" + chType(typ.Elem()) + ")"
|
||||
case reflect.Array:
|
||||
if isUUID(typ) {
|
||||
return chtype.UUID
|
||||
}
|
||||
}
|
||||
|
||||
if s := chType[kind]; s != "" {
|
||||
if s := chTypes[kind]; s != "" {
|
||||
return s
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("ch: unsupported Go type: %s", typ))
|
||||
}
|
||||
|
||||
type NewColumnFunc func(typ reflect.Type, chType string, numRow int) Columnar
|
||||
|
||||
var kindToColumn = [...]NewColumnFunc{
|
||||
reflect.Bool: NewBoolColumn,
|
||||
reflect.Int: NewInt64Column,
|
||||
reflect.Int8: NewInt8Column,
|
||||
reflect.Int16: NewInt16Column,
|
||||
reflect.Int32: NewInt32Column,
|
||||
reflect.Int64: NewInt64Column,
|
||||
reflect.Uint: NewUint64Column,
|
||||
reflect.Uint8: NewUint8Column,
|
||||
reflect.Uint16: NewUint16Column,
|
||||
reflect.Uint32: NewUint32Column,
|
||||
reflect.Uint64: NewUint64Column,
|
||||
reflect.Uintptr: nil,
|
||||
reflect.Float32: NewFloat32Column,
|
||||
reflect.Float64: NewFloat64Column,
|
||||
reflect.Complex64: nil,
|
||||
reflect.Complex128: nil,
|
||||
reflect.Array: nil,
|
||||
reflect.Chan: nil,
|
||||
reflect.Func: nil,
|
||||
reflect.Interface: nil,
|
||||
reflect.Map: NewJSONColumn,
|
||||
reflect.Ptr: nil,
|
||||
reflect.Slice: nil,
|
||||
reflect.String: NewStringColumn,
|
||||
reflect.Struct: NewJSONColumn,
|
||||
reflect.UnsafePointer: nil,
|
||||
}
|
||||
|
||||
// keep in sync with clickhouseType
|
||||
func ColumnFactory(typ reflect.Type, chType string) NewColumnFunc {
|
||||
if chType == chtype.Any {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s := lowCardinalityType(chType); s != "" {
|
||||
switch s {
|
||||
case chtype.String:
|
||||
return NewLCStringColumn
|
||||
}
|
||||
panic(fmt.Errorf("got %s, wanted LowCardinality(String)", chType))
|
||||
}
|
||||
|
||||
if s := enumType(chType); s != "" {
|
||||
return NewEnumColumn
|
||||
}
|
||||
|
||||
if strings.HasPrefix(chType, "SimpleAggregateFunction(") {
|
||||
chType = chSubType(chType, "SimpleAggregateFunction(")
|
||||
} else if s := dateTimeType(chType); s != "" {
|
||||
chType = s
|
||||
}
|
||||
|
||||
switch typ {
|
||||
case timeType:
|
||||
switch chType {
|
||||
case chtype.DateTime:
|
||||
return NewDateTimeColumn
|
||||
case chtype.Date:
|
||||
return NewDateColumn
|
||||
case chtype.Int64:
|
||||
return NewTimeColumn
|
||||
}
|
||||
case ipType:
|
||||
return NewIPColumn
|
||||
}
|
||||
|
||||
kind := typ.Kind()
|
||||
|
||||
switch kind {
|
||||
case reflect.Ptr:
|
||||
if typ.Elem().Kind() == reflect.Struct {
|
||||
return NewJSONColumn
|
||||
}
|
||||
return NullableNewColumnFunc(ColumnFactory(typ.Elem(), nullableType(chType)))
|
||||
case reflect.Slice:
|
||||
switch elem := typ.Elem(); elem.Kind() {
|
||||
case reflect.Ptr:
|
||||
if elem.Elem().Kind() == reflect.Struct {
|
||||
return NewJSONColumn
|
||||
}
|
||||
case reflect.Uint8:
|
||||
if chType == chtype.String {
|
||||
return NewBytesColumn
|
||||
}
|
||||
case reflect.String:
|
||||
return NewStringArrayColumn
|
||||
case reflect.Struct:
|
||||
if elem != timeType {
|
||||
return NewJSONColumn
|
||||
}
|
||||
}
|
||||
|
||||
return NewArrayColumn
|
||||
case reflect.Array:
|
||||
if isUUID(typ) {
|
||||
return NewUUIDColumn
|
||||
}
|
||||
case reflect.Interface:
|
||||
return columnFromCHType(chType)
|
||||
}
|
||||
|
||||
switch chType {
|
||||
case chtype.DateTime:
|
||||
switch typ {
|
||||
case uint32Type:
|
||||
return NewUint32Column
|
||||
case int64Type:
|
||||
return NewInt64TimeColumn
|
||||
default:
|
||||
return NewDateTimeColumn
|
||||
}
|
||||
}
|
||||
|
||||
fn := kindToColumn[kind]
|
||||
if fn != nil {
|
||||
return fn
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("unsupported go_type=%q ch_type=%q", typ.String(), chType))
|
||||
}
|
||||
|
||||
func columnFromCHType(chType string) NewColumnFunc {
|
||||
switch chType {
|
||||
case chtype.String:
|
||||
return NewStringColumn
|
||||
case chtype.UUID:
|
||||
return NewUUIDColumn
|
||||
case chtype.Int8:
|
||||
return NewInt8Column
|
||||
case chtype.Int16:
|
||||
return NewInt16Column
|
||||
case chtype.Int32:
|
||||
return NewInt32Column
|
||||
case chtype.Int64:
|
||||
return NewInt64Column
|
||||
case chtype.UInt8:
|
||||
return NewUint8Column
|
||||
case chtype.UInt16:
|
||||
return NewUint16Column
|
||||
case chtype.UInt32:
|
||||
return NewUint32Column
|
||||
case chtype.UInt64:
|
||||
return NewUint64Column
|
||||
case chtype.Float32:
|
||||
return NewFloat32Column
|
||||
case chtype.Float64:
|
||||
return NewFloat64Column
|
||||
case chtype.DateTime:
|
||||
return NewDateTimeColumn
|
||||
case chtype.Date:
|
||||
return NewDateColumn
|
||||
case chtype.IPv6:
|
||||
return NewIPColumn
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
boolType = reflect.TypeOf(false)
|
||||
int8Type = reflect.TypeOf(int8(0))
|
||||
int16Type = reflect.TypeOf(int16(0))
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uint8Type = reflect.TypeOf(uint8(0))
|
||||
uint16Type = reflect.TypeOf(uint16(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
|
||||
stringType = reflect.TypeOf("")
|
||||
bytesType = reflect.TypeOf((*[]byte)(nil)).Elem()
|
||||
uuidType = reflect.TypeOf((*UUID)(nil)).Elem()
|
||||
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
ipType = reflect.TypeOf((*net.IP)(nil)).Elem()
|
||||
ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem()
|
||||
bfloat16HistType = reflect.TypeOf((*map[chtype.BFloat16]uint64)(nil)).Elem()
|
||||
|
||||
int64SliceType = reflect.TypeOf((*[]int64)(nil)).Elem()
|
||||
uint64SliceType = reflect.TypeOf((*[]uint64)(nil)).Elem()
|
||||
float32SliceType = reflect.TypeOf((*[]float32)(nil)).Elem()
|
||||
float64SliceType = reflect.TypeOf((*[]float64)(nil)).Elem()
|
||||
stringSliceType = reflect.TypeOf((*[]string)(nil)).Elem()
|
||||
)
|
||||
|
||||
func goType(chType string) reflect.Type {
|
||||
switch chType {
|
||||
case chtype.Int8:
|
||||
return int8Type
|
||||
case chtype.Int32:
|
||||
return int32Type
|
||||
case chtype.Int64:
|
||||
return int64Type
|
||||
case chtype.UInt8:
|
||||
return uint8Type
|
||||
case chtype.UInt16:
|
||||
return uint16Type
|
||||
case chtype.UInt32:
|
||||
return uint32Type
|
||||
case chtype.UInt64:
|
||||
return uint64Type
|
||||
case chtype.Float32:
|
||||
return float32Type
|
||||
case chtype.Float64:
|
||||
return float64Type
|
||||
case chtype.String:
|
||||
return stringType
|
||||
case chtype.UUID:
|
||||
return uuidType
|
||||
case chtype.DateTime:
|
||||
return timeType
|
||||
case chtype.Date:
|
||||
return timeType
|
||||
case chtype.IPv6:
|
||||
return ipType
|
||||
default:
|
||||
}
|
||||
|
||||
if s := chArrayElemType(chType); s != "" {
|
||||
return reflect.SliceOf(goType(s))
|
||||
}
|
||||
if s := lowCardinalityType(chType); s != "" {
|
||||
return goType(s)
|
||||
}
|
||||
if s := enumType(chType); s != "" {
|
||||
return stringType
|
||||
}
|
||||
if s := dateTimeType(chType); s != "" {
|
||||
return timeType
|
||||
}
|
||||
if s := nullableType(chType); s != "" {
|
||||
return reflect.PtrTo(goType(s))
|
||||
}
|
||||
if _, funcType := aggFuncNameAndType(chType); funcType != "" {
|
||||
return goType(funcType)
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("unsupported ClickHouse type=%q", chType))
|
||||
}
|
||||
|
||||
func chArrayElemType(s string) string {
|
||||
if s := chSubType(s, "SimpleAggregateFunction("); s != "" {
|
||||
if i := strings.Index(s, ", "); i >= 0 {
|
||||
s = s[i+2:]
|
||||
}
|
||||
return chSubType(s, "Array(")
|
||||
}
|
||||
|
||||
s = chSubType(s, "Array(")
|
||||
if s == "" {
|
||||
return ""
|
||||
@@ -347,15 +310,23 @@ func chArrayElemType(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func lowCardinalityType(s string) string {
|
||||
return chSubType(s, "LowCardinality(")
|
||||
}
|
||||
|
||||
func enumType(s string) string {
|
||||
func chEnumType(s string) string {
|
||||
return chSubType(s, "Enum8(")
|
||||
}
|
||||
|
||||
func dateTimeType(s string) string {
|
||||
func chSimpleAggFunc(s string) string {
|
||||
s = chSubType(s, "SimpleAggregateFunction(")
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
i := strings.Index(s, ", ")
|
||||
if i == -1 {
|
||||
return ""
|
||||
}
|
||||
return s[i+2:]
|
||||
}
|
||||
|
||||
func chDateTimeType(s string) string {
|
||||
s = chSubType(s, "DateTime(")
|
||||
if s == "" {
|
||||
return ""
|
||||
@@ -366,12 +337,36 @@ func dateTimeType(s string) string {
|
||||
return chtype.DateTime
|
||||
}
|
||||
|
||||
func nullableType(s string) string {
|
||||
func isDateTime64Type(s string) bool {
|
||||
return chSubType(s, "DateTime64(") != ""
|
||||
}
|
||||
|
||||
func parseDateTime64Prec(s string) int {
|
||||
s = chSubType(s, "DateTime64(")
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
prec, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return prec
|
||||
}
|
||||
|
||||
func chNullableType(s string) string {
|
||||
return chSubType(s, "Nullable(")
|
||||
}
|
||||
|
||||
func aggFuncNameAndType(chType string) (funcName, funcType string) {
|
||||
s := chSubType(chType, "SimpleAggregateFunction(")
|
||||
var s string
|
||||
|
||||
for _, prefix := range []string{"SimpleAggregateFunction(", "AggregateFunction("} {
|
||||
s = chSubType(chType, prefix)
|
||||
if s != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if s == "" {
|
||||
return "", ""
|
||||
}
|
||||
|
@@ -1,20 +1,22 @@
|
||||
package chtype
|
||||
|
||||
const (
|
||||
Any = "_" // for decoding into interface{}
|
||||
String = "String"
|
||||
UUID = "UUID"
|
||||
Int8 = "Int8"
|
||||
Int16 = "Int16"
|
||||
Int32 = "Int32"
|
||||
Int64 = "Int64"
|
||||
UInt8 = "UInt8"
|
||||
UInt16 = "UInt16"
|
||||
UInt32 = "UInt32"
|
||||
UInt64 = "UInt64"
|
||||
Float32 = "Float32"
|
||||
Float64 = "Float64"
|
||||
DateTime = "DateTime"
|
||||
Date = "Date"
|
||||
IPv6 = "IPv6"
|
||||
Any = "_" // for decoding into interface{}
|
||||
Bool = "Bool"
|
||||
String = "String"
|
||||
UUID = "UUID"
|
||||
Int8 = "Int8"
|
||||
Int16 = "Int16"
|
||||
Int32 = "Int32"
|
||||
Int64 = "Int64"
|
||||
UInt8 = "UInt8"
|
||||
UInt16 = "UInt16"
|
||||
UInt32 = "UInt32"
|
||||
UInt64 = "UInt64"
|
||||
Float32 = "Float32"
|
||||
Float64 = "Float64"
|
||||
DateTime = "DateTime"
|
||||
DateTime64 = "DateTime64"
|
||||
Date = "Date"
|
||||
IPv6 = "IPv6"
|
||||
)
|
||||
|
@@ -1,13 +0,0 @@
|
||||
package chtype
|
||||
|
||||
import "math"
|
||||
|
||||
type BFloat16 uint16
|
||||
|
||||
func ToBFloat16(f float64) BFloat16 {
|
||||
return BFloat16(math.Float32bits(float32(f)) >> 16)
|
||||
}
|
||||
|
||||
func (f BFloat16) Float32() float32 {
|
||||
return math.Float32frombits(uint32(f) << 16)
|
||||
}
|
164
ch/config.go
164
ch/config.go
@@ -17,16 +17,19 @@ import (
|
||||
|
||||
const (
|
||||
discardUnknownColumnsFlag internal.Flag = 1 << iota
|
||||
autoCreateDatabaseFlag
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
chpool.Config
|
||||
|
||||
Network string
|
||||
Compression bool
|
||||
|
||||
Addr string
|
||||
User string
|
||||
Password string
|
||||
Database string
|
||||
Cluster string
|
||||
|
||||
DialTimeout time.Duration
|
||||
TLSConfig *tls.Config
|
||||
@@ -40,37 +43,44 @@ type Config struct {
|
||||
MaxRetryBackoff time.Duration
|
||||
}
|
||||
|
||||
func (cfg *Config) netDialer() *net.Dialer {
|
||||
func (conf *Config) clone() *Config {
|
||||
clone := *conf
|
||||
return &clone
|
||||
}
|
||||
|
||||
func (conf *Config) netDialer() *net.Dialer {
|
||||
return &net.Dialer{
|
||||
Timeout: cfg.DialTimeout,
|
||||
Timeout: conf.DialTimeout,
|
||||
KeepAlive: 5 * time.Minute,
|
||||
}
|
||||
}
|
||||
|
||||
func defaultConfig() *Config {
|
||||
var cfg *Config
|
||||
var conf *Config
|
||||
poolSize := 2 * runtime.GOMAXPROCS(0)
|
||||
cfg = &Config{
|
||||
Network: "tcp",
|
||||
conf = &Config{
|
||||
Config: chpool.Config{
|
||||
PoolSize: poolSize,
|
||||
PoolTimeout: 30 * time.Second,
|
||||
MaxIdleConns: poolSize,
|
||||
ConnMaxIdleTime: 30 * time.Minute,
|
||||
},
|
||||
|
||||
Compression: true,
|
||||
|
||||
Addr: "localhost:9000",
|
||||
User: "default",
|
||||
Database: "default",
|
||||
|
||||
DialTimeout: 5 * time.Second,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
|
||||
MaxRetries: 2,
|
||||
MinRetryBackoff: 500 * time.Millisecond,
|
||||
MaxRetryBackoff: time.Second,
|
||||
|
||||
Config: chpool.Config{
|
||||
PoolSize: poolSize,
|
||||
MaxIdleConns: poolSize,
|
||||
PoolTimeout: 30 * time.Second,
|
||||
},
|
||||
MaxRetries: 3,
|
||||
MinRetryBackoff: time.Millisecond,
|
||||
MaxRetryBackoff: 3 * time.Second,
|
||||
}
|
||||
return cfg
|
||||
return conf
|
||||
}
|
||||
|
||||
type Option func(db *DB)
|
||||
@@ -81,51 +91,70 @@ func WithDiscardUnknownColumns() Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithAddr configures TCP host:port or Unix socket depending on Network.
|
||||
// WithCompression enables/disables LZ4 compression.
|
||||
func WithCompression(enabled bool) Option {
|
||||
return func(db *DB) {
|
||||
db.conf.Compression = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func WithAutoCreateDatabase(enabled bool) Option {
|
||||
return func(db *DB) {
|
||||
db.flags.Set(autoCreateDatabaseFlag)
|
||||
}
|
||||
}
|
||||
|
||||
// WithAddr configures TCP host:port.
|
||||
func WithAddr(addr string) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.Addr = addr
|
||||
db.conf.Addr = addr
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSConfig configures TLS config for secure connections.
|
||||
func WithTLSConfig(cfg *tls.Config) Option {
|
||||
func WithTLSConfig(conf *tls.Config) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.TLSConfig = cfg
|
||||
db.conf.TLSConfig = conf
|
||||
}
|
||||
}
|
||||
|
||||
func WithQuerySettings(params map[string]any) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.QuerySettings = params
|
||||
db.conf.QuerySettings = params
|
||||
}
|
||||
}
|
||||
|
||||
func WithInsecure(on bool) Option {
|
||||
return func(db *DB) {
|
||||
if on {
|
||||
db.cfg.TLSConfig = nil
|
||||
db.conf.TLSConfig = nil
|
||||
} else {
|
||||
db.cfg.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
db.conf.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithUser(user string) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.User = user
|
||||
db.conf.User = user
|
||||
}
|
||||
}
|
||||
|
||||
func WithPassword(password string) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.Password = password
|
||||
db.conf.Password = password
|
||||
}
|
||||
}
|
||||
|
||||
func WithDatabase(database string) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.Database = database
|
||||
db.conf.Database = database
|
||||
}
|
||||
}
|
||||
|
||||
func WithCluster(cluster string) Option {
|
||||
return func(db *DB) {
|
||||
db.conf.Cluster = cluster
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +162,7 @@ func WithDatabase(database string) Option {
|
||||
// Default is 5 seconds.
|
||||
func WithDialTimeout(timeout time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.DialTimeout = timeout
|
||||
db.conf.DialTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +170,7 @@ func WithDialTimeout(timeout time.Duration) Option {
|
||||
// with a timeout instead of blocking.
|
||||
func WithReadTimeout(timeout time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.ReadTimeout = timeout
|
||||
db.conf.ReadTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,15 +178,15 @@ func WithReadTimeout(timeout time.Duration) Option {
|
||||
// with a timeout instead of blocking.
|
||||
func WithWriteTimeout(timeout time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.WriteTimeout = timeout
|
||||
db.conf.WriteTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
func WithTimeout(timeout time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.DialTimeout = timeout
|
||||
db.cfg.ReadTimeout = timeout
|
||||
db.cfg.WriteTimeout = timeout
|
||||
db.conf.DialTimeout = timeout
|
||||
db.conf.ReadTimeout = timeout
|
||||
db.conf.WriteTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +194,7 @@ func WithTimeout(timeout time.Duration) Option {
|
||||
// Default is to retry query 2 times.
|
||||
func WithMaxRetries(maxRetries int) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.MaxRetries = maxRetries
|
||||
db.conf.MaxRetries = maxRetries
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +202,7 @@ func WithMaxRetries(maxRetries int) Option {
|
||||
// Default is 250 milliseconds; -1 disables backoff.
|
||||
func WithMinRetryBackoff(backoff time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.MinRetryBackoff = backoff
|
||||
db.conf.MinRetryBackoff = backoff
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +210,7 @@ func WithMinRetryBackoff(backoff time.Duration) Option {
|
||||
// Default is 4 seconds; -1 disables backoff.
|
||||
func WithMaxRetryBackoff(backoff time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.MaxRetryBackoff = backoff
|
||||
db.conf.MaxRetryBackoff = backoff
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,25 +218,30 @@ func WithMaxRetryBackoff(backoff time.Duration) Option {
|
||||
// Default is 2 connections per every CPU as reported by runtime.NumCPU.
|
||||
func WithPoolSize(poolSize int) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.PoolSize = poolSize
|
||||
db.cfg.MaxIdleConns = poolSize
|
||||
db.conf.PoolSize = poolSize
|
||||
db.conf.MaxIdleConns = poolSize
|
||||
}
|
||||
}
|
||||
|
||||
// WithMinIdleConns configures minimum number of idle connections which is useful when establishing
|
||||
// new connection is slow.
|
||||
func WithMinIdleConns(minIdleConns int) Option {
|
||||
// WithConnMaxLifetime sets the maximum amount of time a connection may be reused.
|
||||
// Expired connections may be closed lazily before reuse.
|
||||
|
||||
// If d <= 0, connections are not closed due to a connection's age.
|
||||
func WithConnMaxLifetime(d time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.MinIdleConns = minIdleConns
|
||||
db.conf.ConnMaxLifetime = d
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxConnAge configures Connection age at which client retires (closes) the connection.
|
||||
// It is useful with proxies like HAProxy.
|
||||
// Default is to not close aged connections.
|
||||
func WithMaxConnAge(timeout time.Duration) Option {
|
||||
// SetConnMaxIdleTime sets the maximum amount of time a connection may be idle.
|
||||
// Expired connections may be closed lazily before reuse.
|
||||
//
|
||||
// If d <= 0, connections are not closed due to a connection's idle time.
|
||||
//
|
||||
// ClickHouse closes idle connections after 1 hour (see idle_connection_timeout).
|
||||
func WithConnMaxIdleTime(d time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.MaxConnAge = timeout
|
||||
db.conf.ConnMaxIdleTime = d
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +251,7 @@ func WithMaxConnAge(timeout time.Duration) Option {
|
||||
// ReadTimeout + 1 second.
|
||||
func WithPoolTimeout(timeout time.Duration) Option {
|
||||
return func(db *DB) {
|
||||
db.cfg.PoolTimeout = timeout
|
||||
db.conf.PoolTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,25 +278,27 @@ func parseDSN(dsn string) ([]Option, error) {
|
||||
|
||||
switch u.Scheme {
|
||||
case "ch", "clickhouse":
|
||||
if u.Host != "" {
|
||||
addr := u.Host
|
||||
if !strings.Contains(addr, ":") {
|
||||
addr += ":5432"
|
||||
}
|
||||
opts = append(opts, WithAddr(addr))
|
||||
}
|
||||
|
||||
if len(u.Path) > 1 {
|
||||
opts = append(opts, WithDatabase(u.Path[1:]))
|
||||
}
|
||||
|
||||
if host := q.string("host"); host != "" {
|
||||
opts = append(opts, WithAddr(host))
|
||||
}
|
||||
// ok
|
||||
default:
|
||||
return nil, errors.New("ch: unknown scheme: " + u.Scheme)
|
||||
}
|
||||
|
||||
if u.Host != "" {
|
||||
addr := u.Host
|
||||
if !strings.Contains(addr, ":") {
|
||||
addr += ":5432"
|
||||
}
|
||||
opts = append(opts, WithAddr(addr))
|
||||
}
|
||||
|
||||
if len(u.Path) > 1 {
|
||||
opts = append(opts, WithDatabase(u.Path[1:]))
|
||||
}
|
||||
|
||||
if host := q.string("host"); host != "" {
|
||||
opts = append(opts, WithAddr(host))
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
opts = append(opts, WithUser(u.User.Username()))
|
||||
if password, ok := u.User.Password(); ok {
|
||||
|
354
ch/db.go
354
ch/db.go
@@ -24,7 +24,7 @@ type DBStats struct {
|
||||
}
|
||||
|
||||
type DB struct {
|
||||
cfg *Config
|
||||
conf *Config
|
||||
pool *chpool.ConnPool
|
||||
|
||||
queryHooks []QueryHook
|
||||
@@ -35,32 +35,38 @@ type DB struct {
|
||||
}
|
||||
|
||||
func Connect(opts ...Option) *DB {
|
||||
db := &DB{
|
||||
cfg: defaultConfig(),
|
||||
db := newDB(defaultConfig(), opts...)
|
||||
if db.flags.Has(autoCreateDatabaseFlag) {
|
||||
db.autoCreateDatabase()
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(db)
|
||||
}
|
||||
db.pool = newConnPool(db.cfg)
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func newConnPool(cfg *Config) *chpool.ConnPool {
|
||||
poolcfg := cfg.Config
|
||||
poolcfg.Dialer = func(ctx context.Context) (net.Conn, error) {
|
||||
if cfg.TLSConfig != nil {
|
||||
func newDB(conf *Config, opts ...Option) *DB {
|
||||
db := &DB{
|
||||
conf: conf,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(db)
|
||||
}
|
||||
db.pool = newConnPool(db.conf)
|
||||
return db
|
||||
}
|
||||
|
||||
func newConnPool(conf *Config) *chpool.ConnPool {
|
||||
poolconf := conf.Config
|
||||
poolconf.Dialer = func(ctx context.Context) (net.Conn, error) {
|
||||
if conf.TLSConfig != nil {
|
||||
return tls.DialWithDialer(
|
||||
cfg.netDialer(),
|
||||
cfg.Network,
|
||||
cfg.Addr,
|
||||
cfg.TLSConfig,
|
||||
conf.netDialer(),
|
||||
"tcp",
|
||||
conf.Addr,
|
||||
conf.TLSConfig,
|
||||
)
|
||||
}
|
||||
return cfg.netDialer().DialContext(ctx, cfg.Network, cfg.Addr)
|
||||
return conf.netDialer().DialContext(ctx, "tcp", conf.Addr)
|
||||
}
|
||||
return chpool.New(&poolcfg)
|
||||
return chpool.New(&poolconf)
|
||||
}
|
||||
|
||||
// Close closes the database client, releasing any open resources.
|
||||
@@ -72,20 +78,20 @@ func (db *DB) Close() error {
|
||||
}
|
||||
|
||||
func (db *DB) String() string {
|
||||
return fmt.Sprintf("DB<addr: %s>", db.cfg.Addr)
|
||||
return fmt.Sprintf("DB<addr: %s>", db.conf.Addr)
|
||||
}
|
||||
|
||||
func (db *DB) Config() *Config {
|
||||
return db.cfg
|
||||
return db.conf
|
||||
}
|
||||
|
||||
func (db *DB) WithTimeout(d time.Duration) *DB {
|
||||
newcfg := *db.cfg
|
||||
newcfg.ReadTimeout = d
|
||||
newcfg.WriteTimeout = d
|
||||
newconf := *db.conf
|
||||
newconf.ReadTimeout = d
|
||||
newconf.WriteTimeout = d
|
||||
|
||||
clone := db.clone()
|
||||
clone.cfg = &newcfg
|
||||
clone.conf = &newconf
|
||||
|
||||
return clone
|
||||
}
|
||||
@@ -106,6 +112,37 @@ func (db *DB) Stats() DBStats {
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) autoCreateDatabase() {
|
||||
ctx := context.Background()
|
||||
|
||||
switch err := db.Ping(ctx); err := err.(type) {
|
||||
case nil: // all is good
|
||||
return
|
||||
case *Error:
|
||||
if err.Code != 81 { // 81 - database does not exist
|
||||
return
|
||||
}
|
||||
default:
|
||||
// ignore the error
|
||||
return
|
||||
}
|
||||
|
||||
conf := db.conf.clone()
|
||||
conf.Database = ""
|
||||
|
||||
query := "CREATE DATABASE IF NOT EXISTS ?"
|
||||
if conf.Cluster != "" {
|
||||
query += " ON CLUSTER ?"
|
||||
}
|
||||
|
||||
tmp := newDB(conf)
|
||||
defer tmp.Close()
|
||||
|
||||
if _, err := tmp.Exec(query, Name(db.conf.Database), Name(db.conf.Cluster)); err != nil {
|
||||
internal.Logger.Printf("create database %q failed: %s", db.conf.Database, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) getConn(ctx context.Context) (*chpool.Conn, error) {
|
||||
cn, err := db.pool.Get(ctx)
|
||||
if err != nil {
|
||||
@@ -157,60 +194,24 @@ func (db *DB) _withConn(ctx context.Context, fn func(*chpool.Conn) error) error
|
||||
return err
|
||||
}
|
||||
|
||||
var done chan struct{}
|
||||
|
||||
if ctxDone := ctx.Done(); ctxDone != nil {
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
select {
|
||||
case <-done:
|
||||
// fn has finished, skip cancel
|
||||
case <-ctxDone:
|
||||
db.cancelConn(ctx, cn)
|
||||
// Signal end of conn use.
|
||||
done <- struct{}{}
|
||||
}
|
||||
}()
|
||||
}
|
||||
var fnErr error
|
||||
|
||||
defer func() {
|
||||
if done != nil {
|
||||
select {
|
||||
case <-done: // wait for cancel to finish request
|
||||
case done <- struct{}{}: // signal fn finish, skip cancel goroutine
|
||||
}
|
||||
}
|
||||
db.releaseConn(cn, err)
|
||||
db.releaseConn(cn, fnErr)
|
||||
}()
|
||||
|
||||
// err is used in releaseConn above
|
||||
err = fn(cn)
|
||||
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||
db.cancelConn(ctx, cn)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) cancelConn(ctx context.Context, cn *chpool.Conn) {
|
||||
if err := cn.WithWriter(ctx, db.cfg.WriteTimeout, func(wr *chproto.Writer) {
|
||||
writeCancel(wr)
|
||||
}); err != nil {
|
||||
internal.Logger.Printf("writeCancel failed: %s", err)
|
||||
}
|
||||
|
||||
_ = cn.Close()
|
||||
fnErr = fn(cn)
|
||||
return fnErr
|
||||
}
|
||||
|
||||
func (db *DB) Ping(ctx context.Context) error {
|
||||
return db.withConn(ctx, func(cn *chpool.Conn) error {
|
||||
if err := cn.WithWriter(ctx, db.cfg.WriteTimeout, func(wr *chproto.Writer) {
|
||||
if err := cn.WithWriter(ctx, db.conf.WriteTimeout, func(wr *chproto.Writer) {
|
||||
writePing(wr)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return cn.WithReader(ctx, db.cfg.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
return cn.WithReader(ctx, db.conf.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
return readPong(rd)
|
||||
})
|
||||
})
|
||||
@@ -225,11 +226,47 @@ func (db *DB) ExecContext(
|
||||
) (sql.Result, error) {
|
||||
query = db.FormatQuery(query, args...)
|
||||
ctx, evt := db.beforeQuery(ctx, nil, query, args, nil)
|
||||
res, err := db.query(ctx, nil, query)
|
||||
res, err := db.exec(ctx, query)
|
||||
db.afterQuery(ctx, evt, res, err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (db *DB) exec(ctx context.Context, query string) (*result, error) {
|
||||
var res *result
|
||||
var lastErr error
|
||||
for attempt := 0; attempt <= db.conf.MaxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
if err := internal.Sleep(ctx, db.retryBackoff()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
res, lastErr = db._exec(ctx, query)
|
||||
if !db.shouldRetry(lastErr) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return res, lastErr
|
||||
}
|
||||
|
||||
func (db *DB) _exec(ctx context.Context, query string) (*result, error) {
|
||||
var res *result
|
||||
err := db.withConn(ctx, func(cn *chpool.Conn) error {
|
||||
if err := cn.WithWriter(ctx, db.conf.WriteTimeout, func(wr *chproto.Writer) {
|
||||
db.writeQuery(ctx, cn, wr, query)
|
||||
db.writeBlock(ctx, wr, nil)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return cn.WithReader(ctx, db.conf.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
var err error
|
||||
res, err = db.readDataBlocks(cn, rd)
|
||||
return err
|
||||
})
|
||||
})
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (db *DB) Query(query string, args ...any) (*Rows, error) {
|
||||
return db.QueryContext(context.Background(), query, args...)
|
||||
}
|
||||
@@ -237,16 +274,16 @@ func (db *DB) Query(query string, args ...any) (*Rows, error) {
|
||||
func (db *DB) QueryContext(
|
||||
ctx context.Context, query string, args ...any,
|
||||
) (*Rows, error) {
|
||||
rows := newRows()
|
||||
query = db.FormatQuery(query, args...)
|
||||
|
||||
ctx, evt := db.beforeQuery(ctx, nil, query, args, nil)
|
||||
res, err := db.query(ctx, rows, query)
|
||||
db.afterQuery(ctx, evt, res, err)
|
||||
blocks, err := db.query(ctx, query)
|
||||
db.afterQuery(ctx, evt, nil, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
|
||||
return newRows(ctx, blocks), nil
|
||||
}
|
||||
|
||||
func (db *DB) QueryRow(query string, args ...any) *Row {
|
||||
@@ -258,50 +295,41 @@ func (db *DB) QueryRowContext(ctx context.Context, query string, args ...any) *R
|
||||
return &Row{rows: rows, err: err}
|
||||
}
|
||||
|
||||
func (db *DB) query(ctx context.Context, model Model, query string) (*result, error) {
|
||||
var res *result
|
||||
func (db *DB) query(ctx context.Context, query string) (*blockIter, error) {
|
||||
var blocks *blockIter
|
||||
var lastErr error
|
||||
for attempt := 0; attempt <= db.cfg.MaxRetries; attempt++ {
|
||||
|
||||
for attempt := 0; attempt <= db.conf.MaxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
lastErr = internal.Sleep(ctx, db.retryBackoff(attempt-1))
|
||||
if lastErr != nil {
|
||||
break
|
||||
if err := internal.Sleep(ctx, db.retryBackoff()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
res, lastErr = db._query(ctx, model, query)
|
||||
blocks, lastErr = db._query(ctx, query)
|
||||
if !db.shouldRetry(lastErr) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if lastErr == nil {
|
||||
if model, ok := model.(AfterScanRowHook); ok {
|
||||
if err := model.AfterScanRow(ctx); err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, lastErr
|
||||
return blocks, lastErr
|
||||
}
|
||||
|
||||
func (db *DB) _query(ctx context.Context, model Model, query string) (*result, error) {
|
||||
var res *result
|
||||
err := db.withConn(ctx, func(cn *chpool.Conn) error {
|
||||
if err := cn.WithWriter(ctx, db.cfg.WriteTimeout, func(wr *chproto.Writer) {
|
||||
db.writeQuery(wr, query)
|
||||
writeBlock(ctx, wr, nil)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return cn.WithReader(ctx, db.cfg.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
var err error
|
||||
res, err = readDataBlocks(rd, model)
|
||||
return err
|
||||
})
|
||||
})
|
||||
return res, err
|
||||
func (db *DB) _query(ctx context.Context, query string) (*blockIter, error) {
|
||||
cn, err := db.getConn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cn.WithWriter(ctx, db.conf.WriteTimeout, func(wr *chproto.Writer) {
|
||||
db.writeQuery(ctx, cn, wr, query)
|
||||
db.writeBlock(ctx, wr, nil)
|
||||
}); err != nil {
|
||||
db.releaseConn(cn, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newBlockIter(db, cn), nil
|
||||
}
|
||||
|
||||
func (db *DB) insert(
|
||||
@@ -312,11 +340,10 @@ func (db *DB) insert(
|
||||
var res *result
|
||||
var lastErr error
|
||||
|
||||
for attempt := 0; attempt <= db.cfg.MaxRetries; attempt++ {
|
||||
for attempt := 0; attempt <= db.conf.MaxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
lastErr = internal.Sleep(ctx, db.retryBackoff(attempt-1))
|
||||
if lastErr != nil {
|
||||
break
|
||||
if err := internal.Sleep(ctx, db.retryBackoff()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,30 +361,30 @@ func (db *DB) _insert(
|
||||
) (*result, error) {
|
||||
var res *result
|
||||
err := db.withConn(ctx, func(cn *chpool.Conn) error {
|
||||
if err := cn.WithWriter(ctx, db.cfg.WriteTimeout, func(wr *chproto.Writer) {
|
||||
db.writeQuery(wr, query)
|
||||
writeBlock(ctx, wr, nil)
|
||||
if err := cn.WithWriter(ctx, db.conf.WriteTimeout, func(wr *chproto.Writer) {
|
||||
db.writeQuery(ctx, cn, wr, query)
|
||||
db.writeBlock(ctx, wr, nil)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cn.WithReader(ctx, db.cfg.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
_, err := readSampleBlock(rd)
|
||||
if err := cn.WithReader(ctx, db.conf.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
_, err := db.readSampleBlock(rd)
|
||||
return err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cn.WithWriter(ctx, db.cfg.WriteTimeout, func(wr *chproto.Writer) {
|
||||
writeBlock(ctx, wr, block)
|
||||
writeBlock(ctx, wr, nil)
|
||||
if err := cn.WithWriter(ctx, db.conf.WriteTimeout, func(wr *chproto.Writer) {
|
||||
db.writeBlock(ctx, wr, block)
|
||||
db.writeBlock(ctx, wr, nil)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cn.WithReader(ctx, db.cfg.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
return cn.WithReader(ctx, db.conf.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
var err error
|
||||
res, err = readPacket(rd)
|
||||
res, err = readPacket(cn, rd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -372,6 +399,10 @@ func (db *DB) NewSelect() *SelectQuery {
|
||||
return NewSelectQuery(db)
|
||||
}
|
||||
|
||||
func (db *DB) NewRaw(query string, args ...any) *RawQuery {
|
||||
return NewRawQuery(db, query, args...)
|
||||
}
|
||||
|
||||
func (db *DB) NewInsert() *InsertQuery {
|
||||
return NewInsertQuery(db)
|
||||
}
|
||||
@@ -388,6 +419,14 @@ func (db *DB) NewTruncateTable() *TruncateTableQuery {
|
||||
return NewTruncateTableQuery(db)
|
||||
}
|
||||
|
||||
func (db *DB) NewCreateView() *CreateViewQuery {
|
||||
return NewCreateViewQuery(db)
|
||||
}
|
||||
|
||||
func (db *DB) NewDropView() *DropViewQuery {
|
||||
return NewDropViewQuery(db)
|
||||
}
|
||||
|
||||
func (db *DB) ResetModel(ctx context.Context, models ...any) error {
|
||||
for _, model := range models {
|
||||
if _, err := db.NewDropTable().Model(model).IfExists().Exec(ctx); err != nil {
|
||||
@@ -412,22 +451,28 @@ func (db *DB) WithFormatter(fmter chschema.Formatter) *DB {
|
||||
|
||||
func (db *DB) shouldRetry(err error) bool {
|
||||
switch err {
|
||||
case driver.ErrBadConn:
|
||||
return true
|
||||
case nil, context.Canceled, context.DeadlineExceeded:
|
||||
return false
|
||||
case driver.ErrBadConn:
|
||||
return true
|
||||
}
|
||||
|
||||
if err, ok := err.(*Error); ok {
|
||||
// https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/ErrorCodes.cpp
|
||||
const (
|
||||
timeoutExceeded = 159
|
||||
tooSlow = 160
|
||||
tooManySimultaneousQueries = 202
|
||||
memoryLimitExceeded = 241
|
||||
cannotDecompress = 271
|
||||
)
|
||||
|
||||
switch err.Code {
|
||||
case timeoutExceeded, tooManySimultaneousQueries, memoryLimitExceeded:
|
||||
case timeoutExceeded,
|
||||
tooSlow,
|
||||
tooManySimultaneousQueries,
|
||||
memoryLimitExceeded,
|
||||
cannotDecompress:
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -435,9 +480,8 @@ func (db *DB) shouldRetry(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *DB) retryBackoff(attempt int) time.Duration {
|
||||
return internal.RetryBackoff(
|
||||
attempt, db.cfg.MinRetryBackoff, db.cfg.MaxRetryBackoff)
|
||||
func (db *DB) retryBackoff() time.Duration {
|
||||
return internal.RetryBackoff(db.conf.MinRetryBackoff, db.conf.MaxRetryBackoff)
|
||||
}
|
||||
|
||||
func (db *DB) FormatQuery(query string, args ...any) string {
|
||||
@@ -454,21 +498,37 @@ func (db *DB) makeQueryBytes() []byte {
|
||||
// Rows is the result of a query. Its cursor starts before the first row of the result set.
|
||||
// Use Next to advance from row to row.
|
||||
type Rows struct {
|
||||
blocks []*chschema.Block
|
||||
ctx context.Context
|
||||
blocks *blockIter
|
||||
block *chschema.Block
|
||||
|
||||
block *chschema.Block
|
||||
blockIndex int
|
||||
rowIndex int
|
||||
rowIndex int
|
||||
hasNext bool
|
||||
closed bool
|
||||
}
|
||||
|
||||
func newRows() *Rows {
|
||||
return new(Rows)
|
||||
func newRows(ctx context.Context, blocks *blockIter) *Rows {
|
||||
return &Rows{
|
||||
ctx: ctx,
|
||||
blocks: blocks,
|
||||
block: new(chschema.Block),
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *Rows) Close() error {
|
||||
if !rs.closed {
|
||||
for rs.blocks.Next(rs.ctx, rs.block) {
|
||||
}
|
||||
rs.close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rs *Rows) close() {
|
||||
rs.closed = true
|
||||
_ = rs.blocks.Close()
|
||||
}
|
||||
|
||||
func (rs *Rows) ColumnTypes() ([]*sql.ColumnType, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
@@ -478,25 +538,25 @@ func (rs *Rows) Columns() ([]string, error) {
|
||||
}
|
||||
|
||||
func (rs *Rows) Err() error {
|
||||
return nil
|
||||
return rs.blocks.Err()
|
||||
}
|
||||
|
||||
func (rs *Rows) Next() bool {
|
||||
if rs.block != nil && rs.rowIndex < rs.block.NumRow {
|
||||
rs.rowIndex++
|
||||
return true
|
||||
if rs.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
for rs.blockIndex < len(rs.blocks) {
|
||||
rs.block = rs.blocks[rs.blockIndex]
|
||||
rs.blockIndex++
|
||||
if rs.block.NumRow > 0 {
|
||||
rs.rowIndex = 1
|
||||
return true
|
||||
for rs.rowIndex >= rs.block.NumRow {
|
||||
if !rs.blocks.Next(rs.ctx, rs.block) {
|
||||
rs.close()
|
||||
return false
|
||||
}
|
||||
rs.rowIndex = 0
|
||||
}
|
||||
|
||||
return false
|
||||
rs.hasNext = true
|
||||
rs.rowIndex++
|
||||
return true
|
||||
}
|
||||
|
||||
func (rs *Rows) NextResultSet() bool {
|
||||
@@ -504,9 +564,14 @@ func (rs *Rows) NextResultSet() bool {
|
||||
}
|
||||
|
||||
func (rs *Rows) Scan(dest ...any) error {
|
||||
if rs.block == nil {
|
||||
if rs.closed {
|
||||
return rs.Err()
|
||||
}
|
||||
|
||||
if !rs.hasNext {
|
||||
return errors.New("ch: Scan called without calling Next")
|
||||
}
|
||||
rs.hasNext = false
|
||||
|
||||
if rs.block.NumColumn != len(dest) {
|
||||
return fmt.Errorf("ch: got %d columns, but Scan has %d values",
|
||||
@@ -522,11 +587,6 @@ func (rs *Rows) Scan(dest ...any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rs *Rows) ScanBlock(block *chschema.Block) error {
|
||||
rs.blocks = append(rs.blocks, block)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Row struct {
|
||||
rows *Rows
|
||||
err error
|
||||
|
153
ch/db_test.go
153
ch/db_test.go
@@ -3,8 +3,12 @@ package ch_test
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -20,7 +24,7 @@ func chDB(opts ...ch.Option) *ch.DB {
|
||||
dsn = "clickhouse://localhost:9000/test?sslmode=disable"
|
||||
}
|
||||
|
||||
opts = append(opts, ch.WithDSN(dsn))
|
||||
opts = append(opts, ch.WithDSN(dsn), ch.WithAutoCreateDatabase(true))
|
||||
db := ch.Connect(opts...)
|
||||
db.AddQueryHook(chdebug.NewQueryHook(
|
||||
chdebug.WithEnabled(false),
|
||||
@@ -29,6 +33,30 @@ func chDB(opts ...ch.Option) *ch.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
func TestAutoCreateDatabase(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
dbName := "auto_create_database"
|
||||
|
||||
{
|
||||
db := ch.Connect()
|
||||
defer db.Close()
|
||||
|
||||
_, err := db.Exec("DROP DATABASE IF EXISTS ?", ch.Name(dbName))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
db := ch.Connect(
|
||||
ch.WithDatabase(dbName),
|
||||
ch.WithAutoCreateDatabase(true),
|
||||
)
|
||||
defer db.Close()
|
||||
|
||||
err := db.Ping(ctx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCHError(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -57,13 +85,6 @@ func TestCHTimeout(t *testing.T) {
|
||||
ctx, "SELECT sleepEachRow(0.01) from numbers(10000) settings max_block_size=10")
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "i/o timeout")
|
||||
|
||||
require.Eventually(t, func() bool {
|
||||
var num int
|
||||
err := db.NewSelect().ColumnExpr("count()").TableExpr("system.processes").Scan(ctx, &num)
|
||||
require.NoError(t, err)
|
||||
return num == 1
|
||||
}, time.Second, 100*time.Millisecond)
|
||||
}
|
||||
|
||||
func TestDSNSetting(t *testing.T) {
|
||||
@@ -139,7 +160,7 @@ func TestPlaceholder(t *testing.T) {
|
||||
params := struct {
|
||||
A int
|
||||
B int
|
||||
Alias ch.Ident
|
||||
Alias ch.Name
|
||||
}{
|
||||
A: 1,
|
||||
B: 2,
|
||||
@@ -244,6 +265,86 @@ func TestScanArrayUint8(t *testing.T) {
|
||||
require.Equal(t, map[string]any{"ns": []uint8{0, 1, 2}}, m)
|
||||
}
|
||||
|
||||
func TestDateTime64(t *testing.T) {
|
||||
type Model struct {
|
||||
Time time.Time `ch:"type:DateTime64(9)"`
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
db := chDB()
|
||||
defer db.Close()
|
||||
|
||||
err := db.ResetModel(ctx, (*Model)(nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
in := &Model{Time: time.Unix(0, 12345678912345)}
|
||||
_, err = db.NewInsert().Model(in).Exec(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
out := new(Model)
|
||||
err = db.NewSelect().Model(out).Scan(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, in.Time.UnixNano(), out.Time.UnixNano())
|
||||
}
|
||||
|
||||
func TestInvalidType(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
db := chDB()
|
||||
defer db.Close()
|
||||
|
||||
var dest struct {
|
||||
Numbers []float32
|
||||
}
|
||||
err := db.NewSelect().
|
||||
ColumnExpr("groupArray(number) AS numbers").
|
||||
TableExpr("numbers(10)").
|
||||
Scan(ctx, &dest)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []float64{}, dest.Numbers)
|
||||
}
|
||||
|
||||
func TestClickhouse(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
db := chDB()
|
||||
defer db.Close()
|
||||
|
||||
tests := []func(ctx context.Context, t *testing.T, db *ch.DB){
|
||||
testWhereBytes,
|
||||
}
|
||||
for _, fn := range tests {
|
||||
t.Run(funcName(fn), func(t *testing.T) {
|
||||
fn(ctx, t, db)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testWhereBytes(ctx context.Context, t *testing.T, db *ch.DB) {
|
||||
type Data struct {
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
err := db.ResetModel(ctx, (*Data)(nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
src, _ := hex.DecodeString("5C00CC")
|
||||
data := &Data{Bytes: src}
|
||||
|
||||
_, err = db.NewInsert().Model(data).Exec(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
got := new(Data)
|
||||
err = db.NewSelect().Model(got).
|
||||
Where("bytes = ?", data.Bytes).
|
||||
Scan(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, data.Bytes, got.Bytes)
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
ch.CHModel `ch:"goch_events,partition:toYYYYMM(created_at)"`
|
||||
|
||||
@@ -282,12 +383,13 @@ func TestORM(t *testing.T) {
|
||||
testORMSlice,
|
||||
testORMColumnarStruct,
|
||||
testORMInvalidEnumValue,
|
||||
testORMInsertSelect,
|
||||
}
|
||||
for _, fn := range tests {
|
||||
_, err := db.NewTruncateTable().Model((*Event)(nil)).Exec(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
t.Run(funcName(fn), func(t *testing.T) {
|
||||
fn(t, db)
|
||||
})
|
||||
}
|
||||
@@ -470,6 +572,37 @@ func testORMInvalidEnumValue(t *testing.T, db *ch.DB) {
|
||||
require.Equal(t, "invalid", dest.Kind)
|
||||
}
|
||||
|
||||
func testORMInsertSelect(t *testing.T, db *ch.DB) {
|
||||
ctx := context.Background()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
src := &Event{
|
||||
ID: 1,
|
||||
Name: "hello",
|
||||
Count: 42,
|
||||
Keys: []string{"foo", "bar"},
|
||||
Values: [][]string{{}, {"hello", "world"}},
|
||||
Kind: "hello",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
_, err := db.NewInsert().Model(src).Exec(ctx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
var dest []Event
|
||||
err := db.NewSelect().Model(&dest).Scan(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 100, len(dest))
|
||||
}
|
||||
|
||||
func funcName(x interface{}) string {
|
||||
s := runtime.FuncForPC(reflect.ValueOf(x).Pointer()).Name()
|
||||
if i := strings.LastIndexByte(s, '.'); i >= 0 {
|
||||
return s[i+1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func strptr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
238
ch/internal/codegen/column.tpl
Normal file
238
ch/internal/codegen/column.tpl
Normal file
@@ -0,0 +1,238 @@
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"time"
|
||||
"reflect"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
{{- range . }}
|
||||
|
||||
{{ if not .IsCustom }}
|
||||
|
||||
type {{ .Name }}Column struct {
|
||||
{{ if gt .Size 0 }}Numeric{{ end }}ColumnOf[{{ .GoType }}]
|
||||
}
|
||||
|
||||
var _ Columnar = (*{{ .Name }}Column)(nil)
|
||||
|
||||
func New{{ .Name }}Column() Columnar {
|
||||
return new({{ .Name }}Column)
|
||||
}
|
||||
|
||||
var _{{ .Name }}Type = reflect.TypeOf((*{{ .GoType }})(nil)).Elem()
|
||||
|
||||
func (c *{{ .Name }}Column) Type() reflect.Type {
|
||||
return _{{ .Name }}Type
|
||||
}
|
||||
|
||||
{{ if .GoReflect }}
|
||||
func (c *{{ .Name }}Column) AppendValue(v reflect.Value) {
|
||||
c.Column = append(c.Column, {{ .GoType }}(v.{{ .GoReflect }}()))
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{ if eq .Size 0 }}
|
||||
|
||||
func (c *{{ .Name }}Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.{{ .Name }}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *{{ .Name }}Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.{{ .Name }}(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type Array{{ .Name }}Column struct {
|
||||
ColumnOf[[]{{ .GoType }}]
|
||||
elem {{ .Name }}Column
|
||||
}
|
||||
|
||||
var (
|
||||
_ Columnar = (*Array{{ .Name }}Column)(nil)
|
||||
_ ArrayColumnar = (*Array{{ .Name }}Column)(nil)
|
||||
)
|
||||
|
||||
func NewArray{{ .Name }}Column() Columnar {
|
||||
return new(Array{{ .Name }}Column)
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) Init(chType string) error {
|
||||
return c.elem.Init(chArrayElemType(chType))
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) Type() reflect.Type {
|
||||
return reflect.TypeOf((*[]{{ .GoType }})(nil)).Elem()
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
offsets, err := c.readOffsets(rd, numRow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.elem.ReadFrom(rd, offsets[len(offsets)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var prev int
|
||||
for i, offset := range offsets {
|
||||
c.Column[i] = c.elem.Column[prev:offset]
|
||||
prev = offset
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) readOffsets(rd *chproto.Reader, numRow int) ([]int, error) {
|
||||
offsets := make([]int, numRow)
|
||||
for i := range offsets {
|
||||
offset, err := rd.UInt64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offsets[i] = int(offset)
|
||||
}
|
||||
return offsets, nil
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) WriteTo(wr *chproto.Writer) error {
|
||||
_ = c.WriteOffset(wr, 0)
|
||||
return c.WriteData(wr)
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) WriteOffset(wr *chproto.Writer, offset int) int {
|
||||
for _, el := range c.Column {
|
||||
offset += len(el)
|
||||
wr.UInt64(uint64(offset))
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
func (c *Array{{ .Name }}Column) WriteData(wr *chproto.Writer) error {
|
||||
for _, ss := range c.Column {
|
||||
c.elem.Column = ss
|
||||
if err := c.elem.WriteTo(wr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type ArrayArray{{ .Name }}Column struct {
|
||||
ColumnOf[[][]{{ .GoType }}]
|
||||
elem Array{{ .Name }}Column
|
||||
}
|
||||
|
||||
var (
|
||||
_ Columnar = (*ArrayArray{{ .Name }}Column)(nil)
|
||||
_ ArrayColumnar = (*ArrayArray{{ .Name }}Column)(nil)
|
||||
)
|
||||
|
||||
func NewArrayArray{{ .Name }}Column() Columnar {
|
||||
return new(ArrayArray{{ .Name }}Column)
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) Init(chType string) error {
|
||||
return c.elem.Init(chArrayElemType(chArrayElemType(chType)))
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) Type() reflect.Type {
|
||||
return reflect.TypeOf((*[][]{{ .GoType }})(nil)).Elem()
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
offsets, err := c.readOffsets(rd, numRow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.elem.ReadFrom(rd, offsets[len(offsets)-1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var prev int
|
||||
for i, offset := range offsets {
|
||||
c.Column[i] = c.elem.Column[prev:offset]
|
||||
prev = offset
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) readOffsets(rd *chproto.Reader, numRow int) ([]int, error) {
|
||||
offsets := make([]int, numRow)
|
||||
for i := range offsets {
|
||||
offset, err := rd.UInt64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offsets[i] = int(offset)
|
||||
}
|
||||
return offsets, nil
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) WriteTo(wr *chproto.Writer) error {
|
||||
_ = c.WriteOffset(wr, 0)
|
||||
return c.WriteData(wr)
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) WriteOffset(wr *chproto.Writer, offset int) int {
|
||||
for _, el := range c.Column {
|
||||
offset += len(el)
|
||||
wr.UInt64(uint64(offset))
|
||||
}
|
||||
|
||||
offset = 0
|
||||
for _, elem := range c.Column {
|
||||
c.elem.Column = elem
|
||||
offset = c.elem.WriteOffset(wr, offset)
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
func (c *ArrayArray{{ .Name }}Column) WriteData(wr *chproto.Writer) error {
|
||||
for _, ss := range c.Column {
|
||||
c.elem.Column = ss
|
||||
if err := c.elem.WriteData(wr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
{{- end }}
|
34
ch/internal/codegen/column_safe.tpl
Normal file
34
ch/internal/codegen/column_safe.tpl
Normal file
@@ -0,0 +1,34 @@
|
||||
//go:build !amd64 && !arm64
|
||||
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
{{- range . }}
|
||||
|
||||
{{ if eq .Size 0 }} {{ continue }} {{ end }}
|
||||
|
||||
func (c *{{ .Name }}Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
for i := range c.Column {
|
||||
n, err := rd.{{ .Name }}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Column[i] = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *{{ .Name }}Column) WriteTo(wr *chproto.Writer) error {
|
||||
for _, n := range c.Column {
|
||||
wr.{{ .Name }}(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
{{- end }}
|
51
ch/internal/codegen/column_unsafe.tpl
Normal file
51
ch/internal/codegen/column_unsafe.tpl
Normal file
@@ -0,0 +1,51 @@
|
||||
//go:build amd64 || arm64
|
||||
|
||||
package chschema
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
)
|
||||
|
||||
{{- range . }}
|
||||
|
||||
{{ if eq .Size 0 }} {{ continue }} {{ end }}
|
||||
|
||||
func (c *{{ .Name }}Column) ReadFrom(rd *chproto.Reader, numRow int) error {
|
||||
const size = {{ .Size }} / 8
|
||||
|
||||
if numRow == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.AllocForReading(numRow)
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
dest := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
_, err := io.ReadFull(rd, dest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *{{ .Name }}Column) WriteTo(wr *chproto.Writer) error {
|
||||
const size = {{ .Size }} / 8
|
||||
|
||||
if len(c.Column) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&c.Column))
|
||||
slice.Len *= size
|
||||
slice.Cap *= size
|
||||
|
||||
src := *(*[]byte)(unsafe.Pointer(&slice))
|
||||
wr.Write(src)
|
||||
return nil
|
||||
}
|
||||
|
||||
{{- end }}
|
@@ -79,24 +79,10 @@ func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration {
|
||||
if retry < 0 {
|
||||
panic("not reached")
|
||||
}
|
||||
if minBackoff == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
d := minBackoff << uint(retry)
|
||||
if d < minBackoff {
|
||||
func RetryBackoff(minBackoff, maxBackoff time.Duration) time.Duration {
|
||||
backoff := minBackoff + time.Duration(rand.Int63n(int64(maxBackoff)))
|
||||
if backoff > maxBackoff {
|
||||
return maxBackoff
|
||||
}
|
||||
|
||||
d = minBackoff + time.Duration(rand.Int63n(int64(d)))
|
||||
|
||||
if d > maxBackoff || d < minBackoff {
|
||||
d = maxBackoff
|
||||
}
|
||||
|
||||
return d
|
||||
return backoff
|
||||
}
|
||||
|
267
ch/proto.go
267
ch/proto.go
@@ -10,30 +10,125 @@ import (
|
||||
"github.com/uptrace/go-clickhouse/ch/chpool"
|
||||
"github.com/uptrace/go-clickhouse/ch/chproto"
|
||||
"github.com/uptrace/go-clickhouse/ch/chschema"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
clientName = "go-clickhouse"
|
||||
chVersionMajor = 19
|
||||
chVersionMinor = 17
|
||||
chVersionPatch = 5
|
||||
chRevision = 54428
|
||||
chVersionMajor = 1
|
||||
chVersionMinor = 1
|
||||
chProtoVersion = chproto.DBMS_TCP_PROTOCOL_VERSION
|
||||
)
|
||||
|
||||
var (
|
||||
osUser = os.Getenv("USER")
|
||||
hostname, _ = os.Hostname()
|
||||
)
|
||||
|
||||
type blockIter struct {
|
||||
db *DB
|
||||
cn *chpool.Conn
|
||||
|
||||
stickyErr error
|
||||
}
|
||||
|
||||
func newBlockIter(db *DB, cn *chpool.Conn) *blockIter {
|
||||
return &blockIter{
|
||||
db: db,
|
||||
cn: cn,
|
||||
}
|
||||
}
|
||||
|
||||
func (it *blockIter) Close() error {
|
||||
if it.cn != nil {
|
||||
it.close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (it *blockIter) close() {
|
||||
it.db.releaseConn(it.cn, it.stickyErr)
|
||||
it.cn = nil
|
||||
}
|
||||
|
||||
func (it *blockIter) Err() error {
|
||||
return it.stickyErr
|
||||
}
|
||||
|
||||
func (it *blockIter) Next(ctx context.Context, block *chschema.Block) bool {
|
||||
if it.cn == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ok, err := it.read(ctx, block)
|
||||
if err != nil {
|
||||
it.stickyErr = err
|
||||
it.close()
|
||||
return false
|
||||
}
|
||||
|
||||
if !ok {
|
||||
it.close()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (it *blockIter) read(ctx context.Context, block *chschema.Block) (bool, error) {
|
||||
rd := it.cn.Reader(ctx, it.db.conf.ReadTimeout)
|
||||
for {
|
||||
packet, err := rd.Uvarint()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch packet {
|
||||
case chproto.ServerData:
|
||||
if err := it.db.readBlock(rd, block, true); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
case chproto.ServerException:
|
||||
return false, readException(rd)
|
||||
case chproto.ServerProgress:
|
||||
if err := readProgress(it.cn, rd); err != nil {
|
||||
return false, err
|
||||
}
|
||||
case chproto.ServerProfileInfo:
|
||||
if err := readProfileInfo(rd); err != nil {
|
||||
return false, err
|
||||
}
|
||||
case chproto.ServerTableColumns:
|
||||
if err := readServerTableColumns(rd); err != nil {
|
||||
return false, err
|
||||
}
|
||||
case chproto.ServerProfileEvents:
|
||||
block := new(chschema.Block)
|
||||
if err := it.db.readBlock(rd, block, false); err != nil {
|
||||
return false, err
|
||||
}
|
||||
case chproto.ServerEndOfStream:
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("ch: blockIter.Next: unexpected packet: %d", packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) hello(ctx context.Context, cn *chpool.Conn) error {
|
||||
err := cn.WithWriter(ctx, db.cfg.WriteTimeout, func(wr *chproto.Writer) {
|
||||
wr.Uvarint(chproto.ClientHello)
|
||||
err := cn.WithWriter(ctx, db.conf.WriteTimeout, func(wr *chproto.Writer) {
|
||||
wr.WriteByte(chproto.ClientHello)
|
||||
writeClientInfo(wr)
|
||||
|
||||
wr.String(db.cfg.Database)
|
||||
wr.String(db.cfg.User)
|
||||
wr.String(db.cfg.Password)
|
||||
wr.String(db.conf.Database)
|
||||
wr.String(db.conf.User)
|
||||
wr.String(db.conf.Password)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cn.WithReader(ctx, db.cfg.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
return cn.WithReader(ctx, db.conf.ReadTimeout, func(rd *chproto.Reader) error {
|
||||
packet, err := rd.Uvarint()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -53,7 +148,7 @@ func writeClientInfo(wr *chproto.Writer) {
|
||||
wr.String(clientName)
|
||||
wr.Uvarint(chVersionMajor)
|
||||
wr.Uvarint(chVersionMinor)
|
||||
wr.Uvarint(chRevision)
|
||||
wr.Uvarint(chProtoVersion)
|
||||
}
|
||||
|
||||
func readException(rd *chproto.Reader) (err error) {
|
||||
@@ -109,7 +204,7 @@ func readProfileInfo(rd *chproto.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func readProgress(rd *chproto.Reader) error {
|
||||
func readProgress(cn *chpool.Conn, rd *chproto.Reader) error {
|
||||
if _, err := rd.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -119,17 +214,19 @@ func readProgress(rd *chproto.Reader) error {
|
||||
if _, err := rd.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := rd.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := rd.Uvarint(); err != nil {
|
||||
return err
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO {
|
||||
if _, err := rd.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := rd.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writePing(wr *chproto.Writer) {
|
||||
wr.Uvarint(chproto.ClientPing)
|
||||
wr.WriteByte(chproto.ClientPing)
|
||||
}
|
||||
|
||||
func readPong(rd *chproto.Reader) error {
|
||||
@@ -152,38 +249,81 @@ func readPong(rd *chproto.Reader) error {
|
||||
}
|
||||
}
|
||||
|
||||
var hostname string
|
||||
|
||||
func (db *DB) writeQuery(wr *chproto.Writer, query string) {
|
||||
if hostname == "" {
|
||||
hostname, _ = os.Hostname()
|
||||
}
|
||||
|
||||
wr.Uvarint(chproto.ClientQuery)
|
||||
wr.String("")
|
||||
func (db *DB) writeQuery(ctx context.Context, cn *chpool.Conn, wr *chproto.Writer, query string) {
|
||||
wr.WriteByte(chproto.ClientQuery)
|
||||
wr.String("") // query id
|
||||
|
||||
// TODO: use QuerySecondary - https://github.com/ClickHouse/ClickHouse/blob/master/dbms/src/Client/Connection.cpp#L388-L404
|
||||
wr.Uvarint(chproto.QueryInitial)
|
||||
wr.WriteByte(chproto.QueryInitial)
|
||||
wr.String("") // initial user
|
||||
wr.String("") // initial query id
|
||||
wr.String("[::ffff:127.0.0.1]:0")
|
||||
wr.Uvarint(1) // iface type TCP
|
||||
wr.String(hostname)
|
||||
wr.String(cn.LocalAddr().String())
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_PROTOCOL_VERSION_WITH_INITIAL_QUERY_START_TIME {
|
||||
wr.Int64(0) // initial_query_start_time_microseconds
|
||||
}
|
||||
wr.WriteByte(1) // interface [tcp - 1, http - 2]
|
||||
wr.String(osUser)
|
||||
wr.String(hostname)
|
||||
writeClientInfo(wr)
|
||||
wr.String("") // quota key
|
||||
wr.Uvarint(chVersionPatch) // client version patch
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO {
|
||||
wr.String("") // quota key
|
||||
}
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_PROTOCOL_VERSION_WITH_DISTRIBUTED_DEPTH {
|
||||
wr.Uvarint(0)
|
||||
}
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_REVISION_WITH_VERSION_PATCH {
|
||||
wr.Uvarint(0) // client version patch
|
||||
}
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_REVISION_WITH_OPENTELEMETRY {
|
||||
if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() {
|
||||
wr.WriteByte(1)
|
||||
{
|
||||
v := spanCtx.TraceID()
|
||||
wr.UUID(v[:])
|
||||
}
|
||||
{
|
||||
v := spanCtx.SpanID()
|
||||
wr.Write(reverseBytes(v[:]))
|
||||
}
|
||||
wr.String(spanCtx.TraceState().String())
|
||||
wr.WriteByte(byte(spanCtx.TraceFlags()))
|
||||
} else {
|
||||
wr.WriteByte(0)
|
||||
}
|
||||
}
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_REVISION_WITH_PARALLEL_REPLICAS {
|
||||
wr.Uvarint(0) // collaborate_with_initiator
|
||||
wr.Uvarint(0) // count_participating_replicas
|
||||
wr.Uvarint(0) // number_of_current_replica
|
||||
}
|
||||
|
||||
db.writeSettings(wr)
|
||||
db.writeSettings(cn, wr)
|
||||
|
||||
wr.Uvarint(2)
|
||||
wr.Uvarint(chproto.CompressionEnabled)
|
||||
if cn.ServerInfo.Revision >= chproto.DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET {
|
||||
wr.String("")
|
||||
}
|
||||
wr.Uvarint(2) // state complete
|
||||
wr.Bool(db.conf.Compression)
|
||||
wr.String(query)
|
||||
}
|
||||
|
||||
func (db *DB) writeSettings(wr *chproto.Writer) {
|
||||
for key, value := range db.cfg.QuerySettings {
|
||||
func reverseBytes(b []byte) []byte {
|
||||
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
|
||||
b[i], b[j] = b[j], b[i]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (db *DB) writeSettings(cn *chpool.Conn, wr *chproto.Writer) {
|
||||
for key, value := range db.conf.QuerySettings {
|
||||
wr.String(key)
|
||||
|
||||
if cn.ServerInfo.Revision > chproto.DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS {
|
||||
wr.Bool(true) // is_important
|
||||
wr.String(fmt.Sprint(value))
|
||||
continue
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
wr.String(value)
|
||||
@@ -198,21 +338,22 @@ func (db *DB) writeSettings(wr *chproto.Writer) {
|
||||
default:
|
||||
panic(fmt.Errorf("%s setting has unsupported type: %T", key, value))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wr.String("")
|
||||
wr.String("") // end of settings
|
||||
}
|
||||
|
||||
var emptyBlock chschema.Block
|
||||
|
||||
func writeBlock(ctx context.Context, wr *chproto.Writer, block *chschema.Block) {
|
||||
func (db *DB) writeBlock(ctx context.Context, wr *chproto.Writer, block *chschema.Block) {
|
||||
if block == nil {
|
||||
block = &emptyBlock
|
||||
}
|
||||
wr.Uvarint(chproto.ClientData)
|
||||
wr.WriteByte(chproto.ClientData)
|
||||
wr.String("")
|
||||
|
||||
wr.WithCompression(func() error {
|
||||
wr.WithCompression(db.conf.Compression, func() error {
|
||||
writeBlockInfo(wr)
|
||||
return block.WriteTo(wr)
|
||||
})
|
||||
@@ -228,7 +369,7 @@ func writeBlockInfo(wr *chproto.Writer) {
|
||||
wr.Uvarint(0)
|
||||
}
|
||||
|
||||
func readSampleBlock(rd *chproto.Reader) (*chschema.Block, error) {
|
||||
func (db *DB) readSampleBlock(rd *chproto.Reader) (*chschema.Block, error) {
|
||||
for {
|
||||
packet, err := rd.Uvarint()
|
||||
if err != nil {
|
||||
@@ -238,7 +379,7 @@ func readSampleBlock(rd *chproto.Reader) (*chschema.Block, error) {
|
||||
switch packet {
|
||||
case chproto.ServerData:
|
||||
block := new(chschema.Block)
|
||||
if err := readBlock(rd, block); err != nil {
|
||||
if err := db.readBlock(rd, block, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return block, nil
|
||||
@@ -254,8 +395,9 @@ func readSampleBlock(rd *chproto.Reader) (*chschema.Block, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func readDataBlocks(rd *chproto.Reader, model Model) (*result, error) {
|
||||
func (db *DB) readDataBlocks(cn *chpool.Conn, rd *chproto.Reader) (*result, error) {
|
||||
var res *result
|
||||
block := new(chschema.Block)
|
||||
for {
|
||||
packet, err := rd.Uvarint()
|
||||
if err != nil {
|
||||
@@ -263,13 +405,8 @@ func readDataBlocks(rd *chproto.Reader, model Model) (*result, error) {
|
||||
}
|
||||
|
||||
switch packet {
|
||||
case chproto.ServerData:
|
||||
block := new(chschema.Block)
|
||||
if model, ok := model.(TableModel); ok {
|
||||
block.Table = model.Table()
|
||||
}
|
||||
|
||||
if err := readBlock(rd, block); err != nil {
|
||||
case chproto.ServerData, chproto.ServerTotals, chproto.ServerExtremes:
|
||||
if err := db.readBlock(rd, block, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -277,16 +414,10 @@ func readDataBlocks(rd *chproto.Reader, model Model) (*result, error) {
|
||||
res = new(result)
|
||||
}
|
||||
res.affected += block.NumRow
|
||||
|
||||
if model != nil {
|
||||
if err := model.ScanBlock(block); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case chproto.ServerException:
|
||||
return nil, readException(rd)
|
||||
case chproto.ServerProgress:
|
||||
if err := readProgress(rd); err != nil {
|
||||
if err := readProgress(cn, rd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case chproto.ServerProfileInfo:
|
||||
@@ -297,6 +428,11 @@ func readDataBlocks(rd *chproto.Reader, model Model) (*result, error) {
|
||||
if err := readServerTableColumns(rd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case chproto.ServerProfileEvents:
|
||||
block := new(chschema.Block)
|
||||
if err := db.readBlock(rd, block, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case chproto.ServerEndOfStream:
|
||||
return res, nil
|
||||
default:
|
||||
@@ -305,7 +441,7 @@ func readDataBlocks(rd *chproto.Reader, model Model) (*result, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func readPacket(rd *chproto.Reader) (*result, error) {
|
||||
func readPacket(cn *chpool.Conn, rd *chproto.Reader) (*result, error) {
|
||||
packet, err := rd.Uvarint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -316,7 +452,7 @@ func readPacket(rd *chproto.Reader) (*result, error) {
|
||||
case chproto.ServerException:
|
||||
return nil, readException(rd)
|
||||
case chproto.ServerProgress:
|
||||
if err := readProgress(rd); err != nil {
|
||||
if err := readProgress(cn, rd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
@@ -337,13 +473,12 @@ func readPacket(rd *chproto.Reader) (*result, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: return block
|
||||
func readBlock(rd *chproto.Reader, block *chschema.Block) error {
|
||||
func (db *DB) readBlock(rd *chproto.Reader, block *chschema.Block, compressible bool) error {
|
||||
if _, err := rd.String(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rd.WithCompression(func() error {
|
||||
return rd.WithCompression(compressible && db.conf.Compression, func() error {
|
||||
if err := readBlockInfo(rd); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -409,10 +544,6 @@ func readBlockInfo(rd *chproto.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeCancel(wr *chproto.Writer) {
|
||||
wr.Uvarint(chproto.ClientCancel)
|
||||
}
|
||||
|
||||
func readServerTableColumns(rd *chproto.Reader) error {
|
||||
_, err := rd.String()
|
||||
if err != nil {
|
||||
|
169
ch/query_base.go
169
ch/query_base.go
@@ -32,6 +32,15 @@ type baseQuery struct {
|
||||
flags internal.Flag
|
||||
}
|
||||
|
||||
func (q *baseQuery) clone() baseQuery {
|
||||
clone := *q
|
||||
clone.with = lazyClone(clone.with)
|
||||
clone.tables = lazyClone(clone.tables)
|
||||
clone.columns = lazyClone(clone.columns)
|
||||
clone.settings = lazyClone(clone.settings)
|
||||
return clone
|
||||
}
|
||||
|
||||
func (q *baseQuery) DB() *DB {
|
||||
return q.db
|
||||
}
|
||||
@@ -94,13 +103,46 @@ func (q *baseQuery) newModel(values ...any) (Model, error) {
|
||||
return q.tableModel, nil
|
||||
}
|
||||
|
||||
func (q *baseQuery) query(ctx context.Context, model Model, query string) (*result, error) {
|
||||
blocks, err := q.db.query(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &result{
|
||||
model: model,
|
||||
}
|
||||
block := new(chschema.Block)
|
||||
if model, ok := model.(TableModel); ok {
|
||||
block.Table = model.Table()
|
||||
}
|
||||
|
||||
for blocks.Next(ctx, block) {
|
||||
if err := model.ScanBlock(block); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.affected += block.NumRow
|
||||
}
|
||||
if err := blocks.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if model, ok := model.(AfterScanRowHook); ok {
|
||||
if err := model.AfterScanRow(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (q *baseQuery) exec(
|
||||
ctx context.Context,
|
||||
iquery Query,
|
||||
query string,
|
||||
) (sql.Result, error) {
|
||||
ctx, event := q.db.beforeQuery(ctx, iquery, query, nil, q.tableModel)
|
||||
res, err := q.db.query(ctx, nil, query)
|
||||
res, err := q.db.exec(ctx, query)
|
||||
q.db.afterQuery(ctx, event, res, err)
|
||||
return res, err
|
||||
}
|
||||
@@ -256,7 +298,7 @@ func (q *baseQuery) addColumn(column chschema.QueryWithArgs) {
|
||||
func (q *baseQuery) excludeColumn(columns []string) {
|
||||
if q.columns == nil {
|
||||
for _, f := range q.table.Fields {
|
||||
q.columns = append(q.columns, chschema.UnsafeIdent(f.CHName))
|
||||
q.columns = append(q.columns, chschema.UnsafeName(f.CHName))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,63 +365,70 @@ func (q *baseQuery) appendSettings(fmter chschema.Formatter, b []byte) (_ []byte
|
||||
return b, nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type WhereQuery struct {
|
||||
where []chschema.QueryWithSep
|
||||
}
|
||||
|
||||
func (q *WhereQuery) addWhere(where chschema.QueryWithSep) {
|
||||
q.where = append(q.where, where)
|
||||
}
|
||||
|
||||
func (q *WhereQuery) WhereGroup(sep string, fn func(*WhereQuery)) {
|
||||
q.addWhereGroup(sep, fn)
|
||||
}
|
||||
|
||||
func (q *WhereQuery) addWhereGroup(sep string, fn func(*WhereQuery)) {
|
||||
q2 := new(WhereQuery)
|
||||
fn(q2)
|
||||
|
||||
if len(q2.where) > 0 {
|
||||
q2.where[0].Sep = ""
|
||||
|
||||
q.addWhere(chschema.SafeQueryWithSep("", nil, sep+"("))
|
||||
q.where = append(q.where, q2.where...)
|
||||
q.addWhere(chschema.SafeQueryWithSep("", nil, ")"))
|
||||
func (q *baseQuery) appendColumns(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
switch {
|
||||
case q.columns != nil:
|
||||
for i, f := range q.columns {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
b, err = f.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case q.table != nil:
|
||||
b = appendTableColumns(b, q.table.CHAlias, q.table.Fields)
|
||||
default:
|
||||
b = append(b, '*')
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type whereBaseQuery struct {
|
||||
baseQuery
|
||||
WhereQuery
|
||||
}
|
||||
|
||||
func (q *whereBaseQuery) mustAppendWhere(fmter chschema.Formatter, b []byte) ([]byte, error) {
|
||||
if len(q.where) == 0 {
|
||||
err := errors.New("ch: Update and Delete queries require at least one Where")
|
||||
return nil, err
|
||||
}
|
||||
return q.appendWhere(fmter, b)
|
||||
}
|
||||
|
||||
func (q *whereBaseQuery) appendWhere(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
if len(q.where) == 0 {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
b = append(b, " WHERE "...)
|
||||
|
||||
b, err = appendWhere(fmter, b, q.where)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func appendTableColumns(b []byte, table chschema.Safe, fields []*chschema.Field) []byte {
|
||||
for i, f := range fields {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
if len(table) > 0 {
|
||||
b = append(b, table...)
|
||||
b = append(b, '.')
|
||||
}
|
||||
b = append(b, f.Column...)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type whereQuery struct {
|
||||
filters []chschema.QueryWithSep
|
||||
}
|
||||
|
||||
func (q *whereQuery) clone() whereQuery {
|
||||
clone := *q
|
||||
clone.filters = lazyClone(clone.filters)
|
||||
return clone
|
||||
}
|
||||
|
||||
func (q *whereQuery) addFilter(filter chschema.QueryWithSep) {
|
||||
q.filters = append(q.filters, filter)
|
||||
}
|
||||
|
||||
func (q *whereQuery) addGroup(sep string, filters []chschema.QueryWithSep) {
|
||||
if len(filters) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
q.addFilter(chschema.SafeQueryWithSep("", nil, sep))
|
||||
q.addFilter(chschema.SafeQueryWithSep("", nil, "("))
|
||||
|
||||
filters[0].Sep = ""
|
||||
q.filters = append(q.filters, filters...)
|
||||
|
||||
q.addFilter(chschema.SafeQueryWithSep("", nil, ")"))
|
||||
}
|
||||
|
||||
func appendWhere(
|
||||
fmter chschema.Formatter, b []byte, where []chschema.QueryWithSep,
|
||||
) (_ []byte, err error) {
|
||||
@@ -388,7 +437,7 @@ func appendWhere(
|
||||
b = append(b, where.Sep...)
|
||||
}
|
||||
|
||||
if where.Query == "" && where.Args == nil {
|
||||
if where.Query == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -401,3 +450,11 @@ func appendWhere(
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func lazyClone[S ~[]E, E any](s S) S {
|
||||
// Preserve nil in case it matters.
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
return s[:len(s):len(s)]
|
||||
}
|
||||
|
@@ -10,17 +10,16 @@ import (
|
||||
)
|
||||
|
||||
type InsertQuery struct {
|
||||
whereBaseQuery
|
||||
baseQuery
|
||||
where whereQuery
|
||||
}
|
||||
|
||||
var _ Query = (*InsertQuery)(nil)
|
||||
|
||||
func NewInsertQuery(db *DB) *InsertQuery {
|
||||
return &InsertQuery{
|
||||
whereBaseQuery: whereBaseQuery{
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -34,7 +33,7 @@ func (q *InsertQuery) Model(model any) *InsertQuery {
|
||||
|
||||
func (q *InsertQuery) Table(tables ...string) *InsertQuery {
|
||||
for _, table := range tables {
|
||||
q.addTable(chschema.UnsafeIdent(table))
|
||||
q.addTable(chschema.UnsafeName(table))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -44,6 +43,11 @@ func (q *InsertQuery) TableExpr(query string, args ...any) *InsertQuery {
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *InsertQuery) ModelTable(table string) *InsertQuery {
|
||||
q.modelTableName = chschema.UnsafeName(table)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *InsertQuery) ModelTableExpr(query string, args ...any) *InsertQuery {
|
||||
q.modelTableName = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
@@ -58,7 +62,7 @@ func (q *InsertQuery) Setting(query string, args ...any) *InsertQuery {
|
||||
|
||||
func (q *InsertQuery) Column(columns ...string) *InsertQuery {
|
||||
for _, column := range columns {
|
||||
q.addColumn(chschema.UnsafeIdent(column))
|
||||
q.addColumn(chschema.UnsafeName(column))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -76,17 +80,12 @@ func (q *InsertQuery) ExcludeColumn(columns ...string) *InsertQuery {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *InsertQuery) Where(query string, args ...any) *InsertQuery {
|
||||
q.addWhere(chschema.SafeQueryWithSep(query, args, " AND "))
|
||||
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *InsertQuery) WhereOr(query string, args ...any) *InsertQuery {
|
||||
q.addWhere(chschema.SafeQueryWithSep(query, args, " OR "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *InsertQuery) WhereGroup(sep string, fn func(*WhereQuery)) *InsertQuery {
|
||||
q.addWhereGroup(sep, fn)
|
||||
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
|
||||
return q
|
||||
}
|
||||
|
||||
@@ -157,10 +156,9 @@ func (q *InsertQuery) appendValues(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(q.where) > 0 {
|
||||
if len(q.where.filters) > 0 {
|
||||
b = append(b, " WHERE "...)
|
||||
|
||||
b, err = appendWhere(fmter, b, q.where)
|
||||
b, err = appendWhere(fmter, b, q.where.filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -191,13 +189,22 @@ func (q *InsertQuery) Exec(ctx context.Context) (sql.Result, error) {
|
||||
}
|
||||
query := internal.String(queryBytes)
|
||||
|
||||
fields, err := q.getFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
ctx, evt := q.db.beforeQuery(ctx, q, query, nil, q.tableModel)
|
||||
|
||||
var res *result
|
||||
var retErr error
|
||||
|
||||
if q.tableModel != nil {
|
||||
fields, err := q.getFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, retErr = q.db.insert(ctx, q.tableModel, query, fields)
|
||||
} else {
|
||||
res, retErr = q.db.exec(ctx, query)
|
||||
}
|
||||
|
||||
ctx, evt := q.db.beforeQuery(ctx, q, query, nil, q.tableModel)
|
||||
res, err := q.db.insert(ctx, q.tableModel, query, fields)
|
||||
q.db.afterQuery(ctx, evt, res, err)
|
||||
return res, err
|
||||
q.db.afterQuery(ctx, evt, res, retErr)
|
||||
|
||||
return res, retErr
|
||||
}
|
||||
|
69
ch/query_raw.go
Normal file
69
ch/query_raw.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package ch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chschema"
|
||||
)
|
||||
|
||||
type RawQuery struct {
|
||||
baseQuery
|
||||
|
||||
query string
|
||||
args []any
|
||||
}
|
||||
|
||||
func NewRawQuery(db *DB, query string, args ...any) *RawQuery {
|
||||
return &RawQuery{
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
query: query,
|
||||
args: args,
|
||||
}
|
||||
}
|
||||
|
||||
func (q *RawQuery) Scan(ctx context.Context, dest ...any) error {
|
||||
return q.scan(ctx, dest, false)
|
||||
}
|
||||
|
||||
func (q *RawQuery) ScanColumns(ctx context.Context, dest ...any) error {
|
||||
return q.scan(ctx, dest, true)
|
||||
}
|
||||
|
||||
func (q *RawQuery) scan(ctx context.Context, dest []any, columnar bool) error {
|
||||
if q.err != nil {
|
||||
return q.err
|
||||
}
|
||||
|
||||
model, err := q.newModel(dest...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := q.db.FormatQuery(q.query, q.args...)
|
||||
|
||||
ctx, evt := q.db.beforeQuery(ctx, q, query, nil, model)
|
||||
res, err := q.baseQuery.query(ctx, model, query)
|
||||
q.db.afterQuery(ctx, evt, res, err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !columnar && useQueryRowModel(model) {
|
||||
if res.affected == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *RawQuery) AppendQuery(fmter chschema.Formatter, b []byte) ([]byte, error) {
|
||||
return fmter.AppendQuery(b, q.query, q.args), nil
|
||||
}
|
||||
|
||||
func (q *RawQuery) Operation() string {
|
||||
return "SELECT"
|
||||
}
|
@@ -13,31 +13,53 @@ import (
|
||||
)
|
||||
|
||||
type SelectQuery struct {
|
||||
whereBaseQuery
|
||||
baseQuery
|
||||
|
||||
sample chschema.QueryWithArgs
|
||||
distinctOn []chschema.QueryWithArgs
|
||||
joins []joinQuery
|
||||
prewhere whereQuery
|
||||
where whereQuery
|
||||
group []chschema.QueryWithArgs
|
||||
having []chschema.QueryWithArgs
|
||||
order []chschema.QueryWithArgs
|
||||
limit int
|
||||
offset int
|
||||
final bool
|
||||
union []union
|
||||
}
|
||||
|
||||
type union struct {
|
||||
expr string
|
||||
query *SelectQuery
|
||||
}
|
||||
|
||||
var _ Query = (*SelectQuery)(nil)
|
||||
|
||||
func NewSelectQuery(db *DB) *SelectQuery {
|
||||
return &SelectQuery{
|
||||
whereBaseQuery: whereBaseQuery{
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (q *SelectQuery) Clone() *SelectQuery {
|
||||
clone := *q
|
||||
|
||||
clone.baseQuery = clone.baseQuery.clone()
|
||||
clone.prewhere = clone.prewhere.clone()
|
||||
clone.where = clone.where.clone()
|
||||
|
||||
clone.distinctOn = lazyClone(clone.distinctOn)
|
||||
clone.joins = lazyClone(clone.joins)
|
||||
clone.group = lazyClone(clone.group)
|
||||
clone.having = lazyClone(clone.having)
|
||||
clone.order = lazyClone(clone.order)
|
||||
|
||||
return &clone
|
||||
}
|
||||
|
||||
func (q *SelectQuery) Operation() string {
|
||||
return "SELECT"
|
||||
}
|
||||
@@ -95,7 +117,7 @@ func (q *SelectQuery) DistinctOn(query string, args ...any) *SelectQuery {
|
||||
|
||||
func (q *SelectQuery) Table(tables ...string) *SelectQuery {
|
||||
for _, table := range tables {
|
||||
q.addTable(chschema.UnsafeIdent(table))
|
||||
q.addTable(chschema.UnsafeName(table))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -105,6 +127,11 @@ func (q *SelectQuery) TableExpr(query string, args ...any) *SelectQuery {
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *SelectQuery) ModelTable(table string) *SelectQuery {
|
||||
q.modelTableName = chschema.UnsafeName(table)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *SelectQuery) ModelTableExpr(query string, args ...any) *SelectQuery {
|
||||
q.modelTableName = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
@@ -119,7 +146,7 @@ func (q *SelectQuery) Sample(query string, args ...any) *SelectQuery {
|
||||
|
||||
func (q *SelectQuery) Column(columns ...string) *SelectQuery {
|
||||
for _, column := range columns {
|
||||
q.addColumn(chschema.UnsafeIdent(column))
|
||||
q.addColumn(chschema.UnsafeName(column))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -136,6 +163,24 @@ func (q *SelectQuery) ExcludeColumn(columns ...string) *SelectQuery {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *SelectQuery) Union(other *SelectQuery) *SelectQuery {
|
||||
return q.addUnion(" UNION ", other)
|
||||
}
|
||||
|
||||
func (q *SelectQuery) UnionAll(other *SelectQuery) *SelectQuery {
|
||||
return q.addUnion(" UNION ALL ", other)
|
||||
}
|
||||
|
||||
func (q *SelectQuery) addUnion(expr string, other *SelectQuery) *SelectQuery {
|
||||
q.union = append(q.union, union{
|
||||
expr: expr,
|
||||
query: other,
|
||||
})
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *SelectQuery) Join(join string, args ...any) *SelectQuery {
|
||||
q.joins = append(q.joins, joinQuery{
|
||||
join: chschema.SafeQuery(join, args),
|
||||
@@ -163,18 +208,53 @@ func (q *SelectQuery) joinOn(cond string, args []any, sep string) *SelectQuery {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *SelectQuery) Prewhere(query string, args ...any) *SelectQuery {
|
||||
q.prewhere.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *SelectQuery) PrewhereOr(query string, args ...any) *SelectQuery {
|
||||
q.prewhere.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *SelectQuery) PrewhereGroup(sep string, fn func(*SelectQuery) *SelectQuery) *SelectQuery {
|
||||
saved := q.prewhere.filters
|
||||
q.prewhere.filters = nil
|
||||
|
||||
q = fn(q)
|
||||
|
||||
filters := q.prewhere.filters
|
||||
q.prewhere.filters = saved
|
||||
|
||||
q.prewhere.addGroup(sep, filters)
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *SelectQuery) Where(query string, args ...any) *SelectQuery {
|
||||
q.addWhere(chschema.SafeQueryWithSep(query, args, " AND "))
|
||||
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *SelectQuery) WhereOr(query string, args ...any) *SelectQuery {
|
||||
q.addWhere(chschema.SafeQueryWithSep(query, args, " OR "))
|
||||
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *SelectQuery) WhereGroup(sep string, fn func(*WhereQuery)) *SelectQuery {
|
||||
q.addWhereGroup(sep, fn)
|
||||
func (q *SelectQuery) WhereGroup(sep string, fn func(*SelectQuery) *SelectQuery) *SelectQuery {
|
||||
saved := q.where.filters
|
||||
q.where.filters = nil
|
||||
|
||||
q = fn(q)
|
||||
|
||||
filters := q.where.filters
|
||||
q.where.filters = saved
|
||||
|
||||
q.where.addGroup(sep, filters)
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
@@ -182,7 +262,7 @@ func (q *SelectQuery) WhereGroup(sep string, fn func(*WhereQuery)) *SelectQuery
|
||||
|
||||
func (q *SelectQuery) Group(columns ...string) *SelectQuery {
|
||||
for _, column := range columns {
|
||||
q.group = append(q.group, chschema.UnsafeIdent(column))
|
||||
q.group = append(q.group, chschema.UnsafeName(column))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -205,7 +285,7 @@ func (q *SelectQuery) Order(orders ...string) *SelectQuery {
|
||||
|
||||
index := strings.IndexByte(order, ' ')
|
||||
if index == -1 {
|
||||
q.order = append(q.order, chschema.UnsafeIdent(order))
|
||||
q.order = append(q.order, chschema.UnsafeName(order))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -216,11 +296,11 @@ func (q *SelectQuery) Order(orders ...string) *SelectQuery {
|
||||
case "ASC", "DESC", "ASC NULLS FIRST", "DESC NULLS FIRST",
|
||||
"ASC NULLS LAST", "DESC NULLS LAST":
|
||||
q.order = append(q.order, chschema.SafeQuery("? ?", []any{
|
||||
Ident(field),
|
||||
Name(field),
|
||||
Safe(sort),
|
||||
}))
|
||||
default:
|
||||
q.order = append(q.order, chschema.UnsafeIdent(order))
|
||||
q.order = append(q.order, chschema.UnsafeName(order))
|
||||
}
|
||||
}
|
||||
return q
|
||||
@@ -278,6 +358,10 @@ func (q *SelectQuery) appendQuery(
|
||||
b = append(b, `WITH "_count_wrapper" AS (`...)
|
||||
}
|
||||
|
||||
if len(q.union) > 0 {
|
||||
b = append(b, '(')
|
||||
}
|
||||
|
||||
if len(q.with) > 0 {
|
||||
b, err = q.appendWith(fmter, b)
|
||||
if err != nil {
|
||||
@@ -316,6 +400,9 @@ func (q *SelectQuery) appendQuery(
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if q.final {
|
||||
b = append(b, " FINAL"...)
|
||||
}
|
||||
if !q.sample.IsZero() {
|
||||
b = append(b, " SAMPLE "...)
|
||||
b, err = q.sample.AppendQuery(fmter, b)
|
||||
@@ -332,9 +419,19 @@ func (q *SelectQuery) appendQuery(
|
||||
}
|
||||
}
|
||||
|
||||
b, err = q.appendWhere(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(q.prewhere.filters) > 0 {
|
||||
b = append(b, " PREWHERE "...)
|
||||
b, err = appendWhere(fmter, b, q.prewhere.filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(q.where.filters) > 0 {
|
||||
b = append(b, " WHERE "...)
|
||||
b, err = appendWhere(fmter, b, q.where.filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(q.group) > 0 {
|
||||
@@ -387,10 +484,23 @@ func (q *SelectQuery) appendQuery(
|
||||
b = append(b, " OFFSET "...)
|
||||
b = strconv.AppendInt(b, int64(q.offset), 10)
|
||||
}
|
||||
if q.final {
|
||||
b = append(b, " FINAL"...)
|
||||
}
|
||||
|
||||
if len(q.union) > 0 {
|
||||
b = append(b, ')')
|
||||
|
||||
for _, u := range q.union {
|
||||
b = append(b, u.expr...)
|
||||
b = append(b, '(')
|
||||
b, err = u.query.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, ')')
|
||||
}
|
||||
} else if cteCount {
|
||||
}
|
||||
|
||||
if cteCount {
|
||||
b = append(b, `) SELECT `...)
|
||||
b = append(b, "count()"...)
|
||||
b = append(b, ` FROM "_count_wrapper"`...)
|
||||
@@ -412,7 +522,7 @@ func (q *SelectQuery) appendWith(fmter chschema.Formatter, b []byte) (_ []byte,
|
||||
}
|
||||
|
||||
if with.cte {
|
||||
b = chschema.AppendIdent(b, with.name)
|
||||
b = chschema.AppendName(b, with.name)
|
||||
b = append(b, " AS "...)
|
||||
b = append(b, "("...)
|
||||
}
|
||||
@@ -426,47 +536,13 @@ func (q *SelectQuery) appendWith(fmter chschema.Formatter, b []byte) (_ []byte,
|
||||
b = append(b, ")"...)
|
||||
} else {
|
||||
b = append(b, " AS "...)
|
||||
b = chschema.AppendIdent(b, with.name)
|
||||
b = chschema.AppendName(b, with.name)
|
||||
}
|
||||
}
|
||||
b = append(b, ' ')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (q *SelectQuery) appendColumns(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
switch {
|
||||
case q.columns != nil:
|
||||
for i, f := range q.columns {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
b, err = f.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case q.table != nil:
|
||||
b = appendTableColumns(b, q.table.CHAlias, q.table.Fields)
|
||||
default:
|
||||
b = append(b, '*')
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func appendTableColumns(b []byte, table chschema.Safe, fields []*chschema.Field) []byte {
|
||||
for i, f := range fields {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
if len(table) > 0 {
|
||||
b = append(b, table...)
|
||||
b = append(b, '.')
|
||||
}
|
||||
b = append(b, f.Column...)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (q *SelectQuery) Scan(ctx context.Context, values ...any) error {
|
||||
return q.scan(ctx, false, values...)
|
||||
}
|
||||
@@ -496,7 +572,7 @@ func (q *SelectQuery) scan(ctx context.Context, columnar bool, values ...any) er
|
||||
query := internal.String(queryBytes)
|
||||
|
||||
ctx, evt := q.db.beforeQuery(ctx, q, query, nil, model)
|
||||
res, err := q.db.query(ctx, model, query)
|
||||
res, err := q.query(ctx, model, query)
|
||||
q.db.afterQuery(ctx, evt, res, err)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -12,6 +12,8 @@ type CreateTableQuery struct {
|
||||
baseQuery
|
||||
|
||||
ifNotExists bool
|
||||
as chschema.QueryWithArgs
|
||||
onCluster chschema.QueryWithArgs
|
||||
engine chschema.QueryWithArgs
|
||||
ttl chschema.QueryWithArgs
|
||||
partition chschema.QueryWithArgs
|
||||
@@ -33,11 +35,15 @@ func (q *CreateTableQuery) Model(model any) *CreateTableQuery {
|
||||
return q
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
func (q *CreateTableQuery) Apply(fn func(*CreateTableQuery) *CreateTableQuery) *CreateTableQuery {
|
||||
return fn(q)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateTableQuery) Table(tables ...string) *CreateTableQuery {
|
||||
for _, table := range tables {
|
||||
q.addTable(chschema.UnsafeIdent(table))
|
||||
q.addTable(chschema.UnsafeName(table))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -47,11 +53,21 @@ func (q *CreateTableQuery) TableExpr(query string, args ...any) *CreateTableQuer
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) ModelTable(table string) *CreateTableQuery {
|
||||
q.modelTableName = chschema.UnsafeName(table)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) ModelTableExpr(query string, args ...any) *CreateTableQuery {
|
||||
q.modelTableName = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) As(table string) *CreateTableQuery {
|
||||
q.as = chschema.UnsafeName(table)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) ColumnExpr(query string, args ...any) *CreateTableQuery {
|
||||
q.addColumn(chschema.SafeQuery(query, args))
|
||||
return q
|
||||
@@ -64,6 +80,11 @@ func (q *CreateTableQuery) IfNotExists() *CreateTableQuery {
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) OnCluster(cluster string) *CreateTableQuery {
|
||||
q.onCluster = chschema.UnsafeName(cluster)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) Engine(query string, args ...any) *CreateTableQuery {
|
||||
q.engine = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
@@ -101,10 +122,6 @@ func (q *CreateTableQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []
|
||||
if q.err != nil {
|
||||
return nil, q.err
|
||||
}
|
||||
if q.table == nil {
|
||||
return nil, errNilModel
|
||||
}
|
||||
|
||||
b = append(b, "CREATE TABLE "...)
|
||||
if q.ifNotExists {
|
||||
b = append(b, "IF NOT EXISTS "...)
|
||||
@@ -115,36 +132,54 @@ func (q *CreateTableQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = append(b, " ("...)
|
||||
|
||||
for i, field := range q.table.Fields {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
|
||||
b = append(b, field.CHName...)
|
||||
b = append(b, " "...)
|
||||
b = append(b, field.CHType...)
|
||||
if field.NotNull {
|
||||
b = append(b, " NOT NULL"...)
|
||||
}
|
||||
if field.CHDefault != "" {
|
||||
b = append(b, " DEFAULT "...)
|
||||
b = append(b, field.CHDefault...)
|
||||
}
|
||||
}
|
||||
|
||||
for i, col := range q.columns {
|
||||
if i > 0 || len(q.table.Fields) > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
b, err = col.AppendQuery(fmter, b)
|
||||
if !q.onCluster.IsEmpty() {
|
||||
b = append(b, " ON CLUSTER "...)
|
||||
b, err = q.onCluster.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
b = append(b, ")"...)
|
||||
if !q.as.IsEmpty() {
|
||||
b = append(b, " AS "...)
|
||||
b, err = q.as.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if q.table != nil {
|
||||
b = append(b, " ("...)
|
||||
|
||||
for i, field := range q.table.Fields {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
|
||||
b = append(b, field.CHName...)
|
||||
b = append(b, " "...)
|
||||
b = append(b, field.CHType...)
|
||||
if field.NotNull {
|
||||
b = append(b, " NOT NULL"...)
|
||||
}
|
||||
if field.CHDefault != "" {
|
||||
b = append(b, " DEFAULT "...)
|
||||
b = append(b, field.CHDefault...)
|
||||
}
|
||||
}
|
||||
|
||||
for i, col := range q.columns {
|
||||
if i > 0 || len(q.table.Fields) > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
b, err = col.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
b = append(b, ")"...)
|
||||
}
|
||||
|
||||
b = append(b, " Engine = "...)
|
||||
|
||||
@@ -171,17 +206,19 @@ func (q *CreateTableQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, ')')
|
||||
} else if len(q.table.PKs) > 0 {
|
||||
b = append(b, " ORDER BY ("...)
|
||||
for i, pk := range q.table.PKs {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
} else if q.table != nil {
|
||||
if len(q.table.PKs) > 0 {
|
||||
b = append(b, " ORDER BY ("...)
|
||||
for i, pk := range q.table.PKs {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
b = append(b, pk.CHName...)
|
||||
}
|
||||
b = append(b, pk.CHName...)
|
||||
b = append(b, ')')
|
||||
} else if q.table.CHEngine == "" {
|
||||
b = append(b, " ORDER BY tuple()"...)
|
||||
}
|
||||
b = append(b, ')')
|
||||
} else if q.table.CHEngine == "" {
|
||||
b = append(b, " ORDER BY tuple()"...)
|
||||
}
|
||||
|
||||
if !q.ttl.IsZero() {
|
||||
@@ -201,7 +238,7 @@ func (q *CreateTableQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []
|
||||
}
|
||||
|
||||
func (q *CreateTableQuery) appendPartition(fmter chschema.Formatter, b []byte) ([]byte, error) {
|
||||
if q.partition.IsZero() && q.table.CHPartition == "" {
|
||||
if q.partition.IsZero() && (q.table == nil || q.table.CHPartition == "") {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,8 @@ import (
|
||||
type DropTableQuery struct {
|
||||
baseQuery
|
||||
|
||||
ifExists bool
|
||||
ifExists bool
|
||||
onCluster chschema.QueryWithArgs
|
||||
}
|
||||
|
||||
var _ Query = (*DropTableQuery)(nil)
|
||||
@@ -34,7 +35,7 @@ func (q *DropTableQuery) Model(model any) *DropTableQuery {
|
||||
|
||||
func (q *DropTableQuery) Table(tables ...string) *DropTableQuery {
|
||||
for _, table := range tables {
|
||||
q.addTable(chschema.UnsafeIdent(table))
|
||||
q.addTable(chschema.UnsafeName(table))
|
||||
}
|
||||
return q
|
||||
}
|
||||
@@ -56,6 +57,11 @@ func (q *DropTableQuery) IfExists() *DropTableQuery {
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropTableQuery) OnCluster(cluster string) *DropTableQuery {
|
||||
q.onCluster = chschema.UnsafeName(cluster)
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *DropTableQuery) Operation() string {
|
||||
@@ -77,6 +83,14 @@ func (q *DropTableQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []by
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !q.onCluster.IsEmpty() {
|
||||
b = append(b, " ON CLUSTER "...)
|
||||
b, err = q.onCluster.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,7 @@ func (q *TruncateTableQuery) Model(model any) *TruncateTableQuery {
|
||||
|
||||
func (q *TruncateTableQuery) Table(tables ...string) *TruncateTableQuery {
|
||||
for _, table := range tables {
|
||||
q.addTable(chschema.UnsafeIdent(table))
|
||||
q.addTable(chschema.UnsafeName(table))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
@@ -76,6 +76,64 @@ func TestQuery(t *testing.T) {
|
||||
Order("id").
|
||||
Setting("ttl_only_drop_parts = 1")
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewDropView().View("view_name")
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewDropView().IfExists().ViewExpr("view_name")
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewCreateView().
|
||||
Materialized().
|
||||
IfNotExists().
|
||||
View("view_name").
|
||||
To("dest_table").
|
||||
Column("col1").
|
||||
ColumnExpr("col1 AS alias").
|
||||
TableExpr("src_table AS alias").
|
||||
Where("foo = bar").
|
||||
Group("group1").
|
||||
GroupExpr("group2, group3").
|
||||
OrderExpr("order2, order3")
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewSelect().
|
||||
Model((*Model)(nil)).
|
||||
Final()
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewSelect().
|
||||
Model((*Model)(nil)).
|
||||
Where("id = ?", 1).
|
||||
Final()
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewSelect().
|
||||
Model((*Model)(nil)).
|
||||
Where("id = ?", 1).
|
||||
Final().
|
||||
Group("id").
|
||||
OrderExpr("id")
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
q1 := db.NewSelect().Model(new(Model)).Where("1")
|
||||
q2 := db.NewSelect().Model(new(Model))
|
||||
return q1.Union(q2)
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
q1 := db.NewSelect().Model(new(Model)).Where("1")
|
||||
q2 := db.NewSelect().Model(new(Model))
|
||||
return q1.UnionAll(q2)
|
||||
},
|
||||
func(db *ch.DB) chschema.QueryAppender {
|
||||
return db.NewCreateTable().
|
||||
Table("my-table_dist").
|
||||
As("my-table").
|
||||
Engine("Distributed(?, currentDatabase(), ?, rand())",
|
||||
ch.Name("my-cluster"), ch.Name("my-table")).
|
||||
OnCluster("my-cluster").
|
||||
IfNotExists()
|
||||
},
|
||||
}
|
||||
|
||||
db := chDB()
|
||||
|
275
ch/query_view_create.go
Normal file
275
ch/query_view_create.go
Normal file
@@ -0,0 +1,275 @@
|
||||
package ch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chschema"
|
||||
"github.com/uptrace/go-clickhouse/ch/internal"
|
||||
)
|
||||
|
||||
type CreateViewQuery struct {
|
||||
baseQuery
|
||||
|
||||
materialized bool
|
||||
ifNotExists bool
|
||||
view chschema.QueryWithArgs
|
||||
onCluster chschema.QueryWithArgs
|
||||
to chschema.QueryWithArgs
|
||||
where whereQuery
|
||||
group []chschema.QueryWithArgs
|
||||
order chschema.QueryWithArgs
|
||||
}
|
||||
|
||||
var _ Query = (*CreateViewQuery)(nil)
|
||||
|
||||
func NewCreateViewQuery(db *DB) *CreateViewQuery {
|
||||
return &CreateViewQuery{
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) Model(model any) *CreateViewQuery {
|
||||
q.setTableModel(model)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) Apply(fn func(*CreateViewQuery) *CreateViewQuery) *CreateViewQuery {
|
||||
return fn(q)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) View(view string) *CreateViewQuery {
|
||||
q.view = chschema.UnsafeName(view)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) ViewExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.view = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) OnCluster(cluster string) *CreateViewQuery {
|
||||
q.onCluster = chschema.UnsafeName(cluster)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) OnClusterExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.onCluster = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) To(to string) *CreateViewQuery {
|
||||
q.to = chschema.UnsafeName(to)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) ToExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.to = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) Table(tables ...string) *CreateViewQuery {
|
||||
for _, table := range tables {
|
||||
q.addTable(chschema.UnsafeName(table))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) TableExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.addTable(chschema.SafeQuery(query, args))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) ModelTableExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.modelTableName = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) Column(columns ...string) *CreateViewQuery {
|
||||
for _, column := range columns {
|
||||
q.addColumn(chschema.UnsafeName(column))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) ColumnExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.addColumn(chschema.SafeQuery(query, args))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) ExcludeColumn(columns ...string) *CreateViewQuery {
|
||||
q.excludeColumn(columns)
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) Materialized() *CreateViewQuery {
|
||||
q.materialized = true
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) IfNotExists() *CreateViewQuery {
|
||||
q.ifNotExists = true
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) Where(query string, args ...any) *CreateViewQuery {
|
||||
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) WhereOr(query string, args ...any) *CreateViewQuery {
|
||||
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) WhereGroup(sep string, fn func(*CreateViewQuery) *CreateViewQuery) *CreateViewQuery {
|
||||
saved := q.where.filters
|
||||
q.where.filters = nil
|
||||
|
||||
q = fn(q)
|
||||
|
||||
filters := q.where.filters
|
||||
q.where.filters = saved
|
||||
|
||||
q.where.addGroup(sep, filters)
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) Group(columns ...string) *CreateViewQuery {
|
||||
for _, column := range columns {
|
||||
q.group = append(q.group, chschema.UnsafeName(column))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) GroupExpr(group string, args ...any) *CreateViewQuery {
|
||||
q.group = append(q.group, chschema.SafeQuery(group, args))
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) OrderExpr(query string, args ...any) *CreateViewQuery {
|
||||
q.order = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *CreateViewQuery) Setting(query string, args ...any) *CreateViewQuery {
|
||||
q.settings = append(q.settings, chschema.SafeQuery(query, args))
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) Operation() string {
|
||||
return "CREATE VIEW"
|
||||
}
|
||||
|
||||
var _ chschema.QueryAppender = (*CreateViewQuery)(nil)
|
||||
|
||||
func (q *CreateViewQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
if q.err != nil {
|
||||
return nil, q.err
|
||||
}
|
||||
|
||||
b = append(b, "CREATE "...)
|
||||
if q.materialized {
|
||||
b = append(b, "MATERIALIZED "...)
|
||||
}
|
||||
b = append(b, "VIEW "...)
|
||||
if q.ifNotExists {
|
||||
b = append(b, "IF NOT EXISTS "...)
|
||||
}
|
||||
|
||||
b, err = q.view.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !q.onCluster.IsEmpty() {
|
||||
b = append(b, " ON CLUSTER "...)
|
||||
b, err = q.onCluster.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
b = append(b, " TO "...)
|
||||
b, err = q.to.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, " AS "...)
|
||||
|
||||
b = append(b, "SELECT "...)
|
||||
|
||||
b, err = q.appendColumns(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = append(b, " FROM "...)
|
||||
b, err = q.appendTablesWithAlias(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(q.where.filters) > 0 {
|
||||
b = append(b, " WHERE "...)
|
||||
b, err = appendWhere(fmter, b, q.where.filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(q.group) > 0 {
|
||||
b = append(b, " GROUP BY "...)
|
||||
for i, f := range q.group {
|
||||
if i > 0 {
|
||||
b = append(b, ", "...)
|
||||
}
|
||||
b, err = f.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !q.order.IsZero() {
|
||||
b = append(b, " ORDER BY "...)
|
||||
b, err = q.order.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
b, err = q.appendSettings(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *CreateViewQuery) Exec(ctx context.Context, dest ...any) (sql.Result, error) {
|
||||
queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := internal.String(queryBytes)
|
||||
|
||||
return q.exec(ctx, q, query)
|
||||
}
|
108
ch/query_view_drop.go
Normal file
108
ch/query_view_drop.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package ch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch/chschema"
|
||||
"github.com/uptrace/go-clickhouse/ch/internal"
|
||||
)
|
||||
|
||||
type DropViewQuery struct {
|
||||
baseQuery
|
||||
|
||||
ifExists bool
|
||||
view chschema.QueryWithArgs
|
||||
onCluster chschema.QueryWithArgs
|
||||
}
|
||||
|
||||
var _ Query = (*DropViewQuery)(nil)
|
||||
|
||||
func NewDropViewQuery(db *DB) *DropViewQuery {
|
||||
q := &DropViewQuery{
|
||||
baseQuery: baseQuery{
|
||||
db: db,
|
||||
},
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) Model(model any) *DropViewQuery {
|
||||
q.setTableModel(model)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) Apply(fn func(*DropViewQuery) *DropViewQuery) *DropViewQuery {
|
||||
return fn(q)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *DropViewQuery) IfExists() *DropViewQuery {
|
||||
q.ifExists = true
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) View(view string) *DropViewQuery {
|
||||
q.view = chschema.UnsafeName(view)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) ViewExpr(query string, args ...any) *DropViewQuery {
|
||||
q.view = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) OnCluster(cluster string) *DropViewQuery {
|
||||
q.onCluster = chschema.UnsafeName(cluster)
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) OnClusterExpr(query string, args ...any) *DropViewQuery {
|
||||
q.onCluster = chschema.SafeQuery(query, args)
|
||||
return q
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *DropViewQuery) Operation() string {
|
||||
return "DROP TABLE"
|
||||
}
|
||||
|
||||
func (q *DropViewQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
|
||||
if q.err != nil {
|
||||
return nil, q.err
|
||||
}
|
||||
|
||||
b = append(b, "DROP VIEW "...)
|
||||
if q.ifExists {
|
||||
b = append(b, "IF EXISTS "...)
|
||||
}
|
||||
|
||||
b, err = q.view.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !q.onCluster.IsEmpty() {
|
||||
b = append(b, " ON CLUSTER "...)
|
||||
b, err = q.onCluster.AppendQuery(fmter, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (q *DropViewQuery) Exec(ctx context.Context, dest ...any) (sql.Result, error) {
|
||||
queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := internal.String(queryBytes)
|
||||
|
||||
return q.exec(ctx, q, query)
|
||||
}
|
1
ch/testdata/snapshots/TestQuery-11
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-11
vendored
Normal file
@@ -0,0 +1 @@
|
||||
DROP VIEW "view_name"
|
1
ch/testdata/snapshots/TestQuery-12
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-12
vendored
Normal file
@@ -0,0 +1 @@
|
||||
DROP VIEW IF EXISTS view_name
|
1
ch/testdata/snapshots/TestQuery-13
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-13
vendored
Normal file
@@ -0,0 +1 @@
|
||||
CREATE MATERIALIZED VIEW IF NOT EXISTS "view_name" TO "dest_table" AS SELECT "col1", col1 AS alias FROM src_table AS alias WHERE (foo = bar) GROUP BY "group1", group2, group3 ORDER BY order2, order3
|
1
ch/testdata/snapshots/TestQuery-14
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-14
vendored
Normal file
@@ -0,0 +1 @@
|
||||
SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model" FINAL
|
1
ch/testdata/snapshots/TestQuery-15
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-15
vendored
Normal file
@@ -0,0 +1 @@
|
||||
SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model" FINAL WHERE (id = 1)
|
1
ch/testdata/snapshots/TestQuery-16
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-16
vendored
Normal file
@@ -0,0 +1 @@
|
||||
SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model" FINAL WHERE (id = 1) GROUP BY "id" ORDER BY id
|
1
ch/testdata/snapshots/TestQuery-17
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-17
vendored
Normal file
@@ -0,0 +1 @@
|
||||
(SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model" WHERE (1)) UNION (SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model")
|
1
ch/testdata/snapshots/TestQuery-18
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-18
vendored
Normal file
@@ -0,0 +1 @@
|
||||
(SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model" WHERE (1)) UNION ALL (SELECT "model"."id", "model"."string", "model"."bytes" FROM "models" AS "model")
|
1
ch/testdata/snapshots/TestQuery-19
vendored
Normal file
1
ch/testdata/snapshots/TestQuery-19
vendored
Normal file
@@ -0,0 +1 @@
|
||||
CREATE TABLE IF NOT EXISTS "my-table_dist" ON CLUSTER "my-cluster" AS "my-table" Engine = Distributed("my-cluster", currentDatabase(), "my-table", rand())
|
@@ -43,14 +43,17 @@ func WithWriter(w io.Writer) Option {
|
||||
// - CHDEBUG=0 - disables the hook.
|
||||
// - CHDEBUG=1 - enables the hook.
|
||||
// - CHDEBUG=2 - enables the hook and verbose mode.
|
||||
func FromEnv(key string) Option {
|
||||
if key == "" {
|
||||
key = "CHDEBUG"
|
||||
func FromEnv(keys ...string) Option {
|
||||
if len(keys) == 0 {
|
||||
keys = []string{"CHDEBUG"}
|
||||
}
|
||||
return func(h *QueryHook) {
|
||||
if env, ok := os.LookupEnv(key); ok {
|
||||
h.enabled = env != "" && env != "0"
|
||||
h.verbose = env == "2"
|
||||
for _, key := range keys {
|
||||
if env, ok := os.LookupEnv(key); ok {
|
||||
h.enabled = env != "" && env != "0"
|
||||
h.verbose = env == "2"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,16 +5,18 @@ go 1.18
|
||||
replace github.com/uptrace/go-clickhouse => ./..
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/uptrace/go-clickhouse v0.3.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
||||
|
@@ -2,26 +2,28 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnL
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
164
chmigrate/chmigrate_test.go
Normal file
164
chmigrate/chmigrate_test.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package chmigrate_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/uptrace/go-clickhouse/ch"
|
||||
"github.com/uptrace/go-clickhouse/chdebug"
|
||||
"github.com/uptrace/go-clickhouse/chmigrate"
|
||||
)
|
||||
|
||||
func TestMigrate(t *testing.T) {
|
||||
type Test struct {
|
||||
run func(t *testing.T, db *ch.DB)
|
||||
}
|
||||
|
||||
tests := []Test{
|
||||
{run: testChmigrateUpAndDown},
|
||||
{run: testChmigrateUpError},
|
||||
}
|
||||
|
||||
db := chDB()
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(funcName(test.run), func(t *testing.T) {
|
||||
test.run(t, db)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testChmigrateUpAndDown(t *testing.T, db *ch.DB) {
|
||||
ctx := context.Background()
|
||||
|
||||
var history []string
|
||||
|
||||
migrations := chmigrate.NewMigrations()
|
||||
migrations.Add(chmigrate.Migration{
|
||||
Name: "20060102150405",
|
||||
Up: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "up1")
|
||||
return nil
|
||||
},
|
||||
Down: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "down1")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
migrations.Add(chmigrate.Migration{
|
||||
Name: "20060102160405",
|
||||
Up: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "up2")
|
||||
return nil
|
||||
},
|
||||
Down: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "down2")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
m := chmigrate.NewMigrator(db, migrations)
|
||||
err := m.Reset(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
group, err := m.Migrate(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), group.ID)
|
||||
require.Len(t, group.Migrations, 2)
|
||||
require.Equal(t, []string{"up1", "up2"}, history)
|
||||
|
||||
history = nil
|
||||
group, err = m.Rollback(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), group.ID)
|
||||
require.Len(t, group.Migrations, 2)
|
||||
require.Equal(t, []string{"down2", "down1"}, history)
|
||||
}
|
||||
|
||||
func testChmigrateUpError(t *testing.T, db *ch.DB) {
|
||||
ctx := context.Background()
|
||||
|
||||
var history []string
|
||||
|
||||
migrations := chmigrate.NewMigrations()
|
||||
migrations.Add(chmigrate.Migration{
|
||||
Name: "20060102150405",
|
||||
Up: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "up1")
|
||||
return nil
|
||||
},
|
||||
Down: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "down1")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
migrations.Add(chmigrate.Migration{
|
||||
Name: "20060102160405",
|
||||
Up: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "up2")
|
||||
return errors.New("failed")
|
||||
},
|
||||
Down: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "down2")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
migrations.Add(chmigrate.Migration{
|
||||
Name: "20060102170405",
|
||||
Up: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "up3")
|
||||
return errors.New("failed")
|
||||
},
|
||||
Down: func(ctx context.Context, db *ch.DB) error {
|
||||
history = append(history, "down3")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
m := chmigrate.NewMigrator(db, migrations)
|
||||
err := m.Reset(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
group, err := m.Migrate(ctx)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "failed", err.Error())
|
||||
require.Equal(t, int64(1), group.ID)
|
||||
require.Len(t, group.Migrations, 2)
|
||||
require.Equal(t, []string{"up1", "up2"}, history)
|
||||
|
||||
history = nil
|
||||
group, err = m.Rollback(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), group.ID)
|
||||
require.Len(t, group.Migrations, 2)
|
||||
require.Equal(t, []string{"down2", "down1"}, history)
|
||||
}
|
||||
|
||||
func chDB(opts ...ch.Option) *ch.DB {
|
||||
dsn := os.Getenv("CH")
|
||||
if dsn == "" {
|
||||
dsn = "clickhouse://localhost:9000/test?sslmode=disable"
|
||||
}
|
||||
|
||||
opts = append(opts, ch.WithDSN(dsn))
|
||||
db := ch.Connect(opts...)
|
||||
db.AddQueryHook(chdebug.NewQueryHook(
|
||||
chdebug.WithEnabled(false),
|
||||
chdebug.FromEnv("CHDEBUG"),
|
||||
))
|
||||
return db
|
||||
}
|
||||
|
||||
func funcName(x interface{}) string {
|
||||
s := runtime.FuncForPC(reflect.ValueOf(x).Pointer()).Name()
|
||||
if i := strings.LastIndexByte(s, '.'); i >= 0 {
|
||||
return s[i+1:]
|
||||
}
|
||||
return s
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -14,9 +15,8 @@ import (
|
||||
)
|
||||
|
||||
type Migration struct {
|
||||
ch.CHModel `ch:"engine:CollapsingMergeTree(sign)"`
|
||||
|
||||
Name string `ch:",pk"`
|
||||
Comment string `ch:"-"`
|
||||
GroupID int64
|
||||
MigratedAt time.Time
|
||||
Sign int8
|
||||
@@ -26,7 +26,7 @@ type Migration struct {
|
||||
}
|
||||
|
||||
func (m *Migration) String() string {
|
||||
return m.Name
|
||||
return fmt.Sprintf("%s_%s", m.Name, m.Comment)
|
||||
}
|
||||
|
||||
func (m *Migration) IsApplied() bool {
|
||||
@@ -41,45 +41,48 @@ func NewSQLMigrationFunc(fsys fs.FS, name string) MigrationFunc {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Exec(ctx, db, f)
|
||||
}
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
var queries []string
|
||||
// Exec reads and executes the SQL migration in the f.
|
||||
func Exec(ctx context.Context, db *ch.DB, f io.Reader) error {
|
||||
scanner := bufio.NewScanner(f)
|
||||
var queries []string
|
||||
|
||||
var query []byte
|
||||
for scanner.Scan() {
|
||||
b := scanner.Bytes()
|
||||
var query []byte
|
||||
for scanner.Scan() {
|
||||
b := scanner.Bytes()
|
||||
|
||||
const prefix = "--migration:"
|
||||
if bytes.HasPrefix(b, []byte(prefix)) {
|
||||
b = b[len(prefix):]
|
||||
if bytes.Equal(b, []byte("split")) {
|
||||
queries = append(queries, string(query))
|
||||
query = query[:0]
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("ch: unknown directive: %q", b)
|
||||
const prefix = "--migration:"
|
||||
if bytes.HasPrefix(b, []byte(prefix)) {
|
||||
b = b[len(prefix):]
|
||||
if bytes.Equal(b, []byte("split")) {
|
||||
queries = append(queries, string(query))
|
||||
query = query[:0]
|
||||
continue
|
||||
}
|
||||
|
||||
query = append(query, b...)
|
||||
query = append(query, '\n')
|
||||
return fmt.Errorf("ch: unknown directive: %q", b)
|
||||
}
|
||||
|
||||
if len(query) > 0 {
|
||||
queries = append(queries, string(query))
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
query = append(query, b...)
|
||||
query = append(query, '\n')
|
||||
}
|
||||
|
||||
if len(query) > 0 {
|
||||
queries = append(queries, string(query))
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
if _, err := db.ExecContext(ctx, q); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
_, err = db.ExecContext(ctx, q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const goTemplate = `package %s
|
||||
@@ -128,7 +131,7 @@ func (ms MigrationSlice) String() string {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(ms[i].Name)
|
||||
sb.WriteString(ms[i].String())
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
|
@@ -50,15 +50,16 @@ func (m *Migrations) MustRegister(up, down MigrationFunc) {
|
||||
|
||||
func (m *Migrations) Register(up, down MigrationFunc) error {
|
||||
fpath := migrationFile()
|
||||
name, err := extractMigrationName(fpath)
|
||||
name, comment, err := extractMigrationName(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Add(Migration{
|
||||
Name: name,
|
||||
Up: up,
|
||||
Down: down,
|
||||
Name: name,
|
||||
Comment: comment,
|
||||
Up: up,
|
||||
Down: down,
|
||||
})
|
||||
|
||||
return nil
|
||||
@@ -89,7 +90,7 @@ func (m *Migrations) Discover(fsys fs.FS) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
name, err := extractMigrationName(path)
|
||||
name, comment, err := extractMigrationName(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -98,6 +99,8 @@ func (m *Migrations) Discover(fsys fs.FS) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
migration.Comment = comment
|
||||
migrationFunc := NewSQLMigrationFunc(fsys, path)
|
||||
|
||||
if strings.HasSuffix(path, ".up.sql") {
|
||||
@@ -154,15 +157,15 @@ func migrationFile() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
var fnameRE = regexp.MustCompile(`^(\d{14})_[0-9a-z_\-]+\.`)
|
||||
var fnameRE = regexp.MustCompile(`^(\d{14})_([0-9a-z_\-]+)\.`)
|
||||
|
||||
func extractMigrationName(fpath string) (string, error) {
|
||||
func extractMigrationName(fpath string) (string, string, error) {
|
||||
fname := filepath.Base(fpath)
|
||||
|
||||
matches := fnameRE.FindStringSubmatch(fname)
|
||||
if matches == nil {
|
||||
return "", fmt.Errorf("chmigrate: unsupported migration name format: %q", fname)
|
||||
return "", "", fmt.Errorf("chmigrate: unsupported migration name format: %q", fname)
|
||||
}
|
||||
|
||||
return matches[1], nil
|
||||
return matches[1], matches[2], nil
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ type MigratorOption func(m *Migrator)
|
||||
|
||||
func WithTableName(table string) MigratorOption {
|
||||
return func(m *Migrator) {
|
||||
m.table = table
|
||||
m.migrationsTable = table
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,14 +27,44 @@ func WithLocksTableName(table string) MigratorOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithReplicated(on bool) MigratorOption {
|
||||
return func(m *Migrator) {
|
||||
m.replicated = on
|
||||
}
|
||||
}
|
||||
|
||||
func WithDistributed(on bool) MigratorOption {
|
||||
return func(m *Migrator) {
|
||||
m.distributed = on
|
||||
}
|
||||
}
|
||||
|
||||
func WithOnCluster(cluster string) MigratorOption {
|
||||
return func(m *Migrator) {
|
||||
m.cluster = cluster
|
||||
}
|
||||
}
|
||||
|
||||
// WithMarkAppliedOnSuccess sets the migrator to only mark migrations as applied/unapplied
|
||||
// when their up/down is successful.
|
||||
func WithMarkAppliedOnSuccess(enabled bool) MigratorOption {
|
||||
return func(m *Migrator) {
|
||||
m.markAppliedOnSuccess = enabled
|
||||
}
|
||||
}
|
||||
|
||||
type Migrator struct {
|
||||
db *ch.DB
|
||||
migrations *Migrations
|
||||
|
||||
ms MigrationSlice
|
||||
|
||||
table string
|
||||
locksTable string
|
||||
migrationsTable string
|
||||
locksTable string
|
||||
replicated bool
|
||||
distributed bool
|
||||
cluster string
|
||||
markAppliedOnSuccess bool
|
||||
}
|
||||
|
||||
func NewMigrator(db *ch.DB, migrations *Migrations, opts ...MigratorOption) *Migrator {
|
||||
@@ -44,8 +74,8 @@ func NewMigrator(db *ch.DB, migrations *Migrations, opts ...MigratorOption) *Mig
|
||||
|
||||
ms: migrations.ms,
|
||||
|
||||
table: "ch_migrations",
|
||||
locksTable: "ch_migration_locks",
|
||||
migrationsTable: "ch_migrations",
|
||||
locksTable: "ch_migration_locks",
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(m)
|
||||
@@ -66,7 +96,7 @@ func (m *Migrator) MigrationsWithStatus(ctx context.Context) (MigrationSlice, er
|
||||
func (m *Migrator) migrationsWithStatus(ctx context.Context) (MigrationSlice, int64, error) {
|
||||
sorted := m.migrations.Sorted()
|
||||
|
||||
applied, err := m.selectAppliedMigrations(ctx)
|
||||
applied, err := m.AppliedMigrations(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@@ -84,37 +114,76 @@ func (m *Migrator) migrationsWithStatus(ctx context.Context) (MigrationSlice, in
|
||||
}
|
||||
|
||||
func (m *Migrator) Init(ctx context.Context) error {
|
||||
if m.distributed {
|
||||
if m.cluster == "" {
|
||||
return errors.New("chmigrate: distributed requires a cluster name")
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := m.db.NewCreateTable().
|
||||
Model((*Migration)(nil)).
|
||||
ModelTableExpr(m.table).
|
||||
Apply(func(q *ch.CreateTableQuery) *ch.CreateTableQuery {
|
||||
if m.replicated {
|
||||
return q.Engine("ReplicatedCollapsingMergeTree(sign)")
|
||||
}
|
||||
return q.Engine("CollapsingMergeTree(sign)")
|
||||
}).
|
||||
ModelTable(m.migrationsTable).
|
||||
OnCluster(m.cluster).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := m.db.NewCreateTable().
|
||||
Model((*migrationLock)(nil)).
|
||||
ModelTableExpr(m.locksTable).
|
||||
Apply(func(q *ch.CreateTableQuery) *ch.CreateTableQuery {
|
||||
if m.replicated {
|
||||
return q.Engine("ReplicatedMergeTree")
|
||||
}
|
||||
return q.Engine("MergeTree")
|
||||
}).
|
||||
ModelTable(m.locksTable).
|
||||
OnCluster(m.cluster).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.distributed {
|
||||
if _, err := m.db.NewCreateTable().
|
||||
Table(m.distTable(m.migrationsTable)).
|
||||
As(m.migrationsTable).
|
||||
Engine("Distributed(?, currentDatabase(), ?, rand())",
|
||||
ch.Ident(m.cluster), ch.Ident(m.migrationsTable)).
|
||||
OnCluster(m.cluster).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) Reset(ctx context.Context) error {
|
||||
if _, err := m.db.NewDropTable().
|
||||
Model((*Migration)(nil)).
|
||||
ModelTableExpr(m.table).
|
||||
IfExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
tables := []string{
|
||||
m.migrationsTable,
|
||||
m.locksTable,
|
||||
}
|
||||
if _, err := m.db.NewDropTable().
|
||||
Model((*migrationLock)(nil)).
|
||||
ModelTableExpr(m.locksTable).
|
||||
IfExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
if m.distributed {
|
||||
tables = append(tables,
|
||||
m.distTable(m.migrationsTable),
|
||||
)
|
||||
}
|
||||
for _, tableName := range tables {
|
||||
if _, err := m.db.NewDropTable().
|
||||
Table(tableName).
|
||||
OnCluster(m.cluster).
|
||||
IfExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return m.Init(ctx)
|
||||
}
|
||||
@@ -127,41 +196,51 @@ func (m *Migrator) Migrate(ctx context.Context, opts ...MigrationOption) (*Migra
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := m.Lock(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer m.Unlock(ctx) //nolint:errcheck
|
||||
|
||||
migrations, lastGroupID, err := m.migrationsWithStatus(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
group := &MigrationGroup{
|
||||
Migrations: migrations.Unapplied(),
|
||||
// Get the unapplied migrations we will range over and apply
|
||||
migrations = migrations.Unapplied()
|
||||
if len(migrations) == 0 {
|
||||
return &MigrationGroup{}, nil
|
||||
}
|
||||
if len(group.Migrations) == 0 {
|
||||
return group, nil
|
||||
}
|
||||
group.ID = lastGroupID + 1
|
||||
|
||||
for i := range group.Migrations {
|
||||
migration := &group.Migrations[i]
|
||||
migration.GroupID = group.ID
|
||||
// Create empty group to track applied migrations
|
||||
applied := new(MigrationGroup)
|
||||
applied.ID = lastGroupID + 1
|
||||
|
||||
// Always mark migration as applied so the rollback has a chance to fix the database.
|
||||
if err := m.MarkApplied(ctx, migration); err != nil {
|
||||
return nil, err
|
||||
for i := range migrations {
|
||||
migration := &migrations[i]
|
||||
migration.GroupID = applied.ID
|
||||
|
||||
if !m.markAppliedOnSuccess {
|
||||
if err := m.MarkApplied(ctx, migration); err != nil {
|
||||
return applied, err
|
||||
}
|
||||
|
||||
// Add to the group before upping the migration when always marking applied
|
||||
applied.Migrations = append(applied.Migrations, *migration)
|
||||
}
|
||||
|
||||
if !cfg.nop && migration.Up != nil {
|
||||
if err := migration.Up(ctx, m.db); err != nil {
|
||||
return group, err
|
||||
return applied, err
|
||||
}
|
||||
}
|
||||
|
||||
if m.markAppliedOnSuccess {
|
||||
if err := m.MarkApplied(ctx, migration); err != nil {
|
||||
return applied, err
|
||||
}
|
||||
|
||||
// Add to the group after upping the migration when marking applied on success
|
||||
applied.Migrations = append(applied.Migrations, *migration)
|
||||
}
|
||||
}
|
||||
|
||||
return group, nil
|
||||
return applied, nil
|
||||
}
|
||||
|
||||
func (m *Migrator) Rollback(ctx context.Context, opts ...MigrationOption) (*MigrationGroup, error) {
|
||||
@@ -171,11 +250,6 @@ func (m *Migrator) Rollback(ctx context.Context, opts ...MigrationOption) (*Migr
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := m.Lock(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer m.Unlock(ctx) //nolint:errcheck
|
||||
|
||||
migrations, err := m.MigrationsWithStatus(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -183,17 +257,35 @@ func (m *Migrator) Rollback(ctx context.Context, opts ...MigrationOption) (*Migr
|
||||
|
||||
lastGroup := migrations.LastGroup()
|
||||
|
||||
// Create empty group to track unapplied migrations
|
||||
unapplied := new(MigrationGroup)
|
||||
unapplied.ID = lastGroup.ID
|
||||
|
||||
for i := len(lastGroup.Migrations) - 1; i >= 0; i-- {
|
||||
migration := &lastGroup.Migrations[i]
|
||||
|
||||
if !m.markAppliedOnSuccess {
|
||||
if err := m.MarkUnapplied(ctx, migration); err != nil {
|
||||
return unapplied, err
|
||||
}
|
||||
|
||||
// Add to the group before downing the migration when always marking unapplied
|
||||
unapplied.Migrations = append(unapplied.Migrations, *migration)
|
||||
}
|
||||
|
||||
if !cfg.nop && migration.Down != nil {
|
||||
if err := migration.Down(ctx, m.db); err != nil {
|
||||
return nil, err
|
||||
return unapplied, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.MarkUnapplied(ctx, migration); err != nil {
|
||||
return nil, err
|
||||
if m.markAppliedOnSuccess {
|
||||
if err := m.MarkUnapplied(ctx, migration); err != nil {
|
||||
return unapplied, err
|
||||
}
|
||||
|
||||
// Add to the group after downing the migration when marking unapplied on success
|
||||
unapplied.Migrations = append(unapplied.Migrations, *migration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +393,7 @@ func (m *Migrator) MarkApplied(ctx context.Context, migration *Migration) error
|
||||
migration.MigratedAt = time.Now()
|
||||
_, err := m.db.NewInsert().
|
||||
Model(migration).
|
||||
ModelTableExpr(m.table).
|
||||
ModelTable(m.distTable(m.migrationsTable)).
|
||||
Exec(ctx)
|
||||
return err
|
||||
}
|
||||
@@ -311,18 +403,41 @@ func (m *Migrator) MarkUnapplied(ctx context.Context, migration *Migration) erro
|
||||
migration.Sign = -1
|
||||
_, err := m.db.NewInsert().
|
||||
Model(migration).
|
||||
ModelTableExpr(m.table).
|
||||
ModelTable(m.distTable(m.migrationsTable)).
|
||||
Exec(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// selectAppliedMigrations selects applied (applied) migrations in descending order.
|
||||
func (m *Migrator) selectAppliedMigrations(ctx context.Context) (MigrationSlice, error) {
|
||||
func (m *Migrator) TruncateTable(ctx context.Context) error {
|
||||
_, err := m.db.Exec("TRUNCATE TABLE ?", ch.Ident(m.distTable(m.migrationsTable)))
|
||||
return err
|
||||
}
|
||||
|
||||
// MissingMigrations returns applied migrations that can no longer be found.
|
||||
func (m *Migrator) MissingMigrations(ctx context.Context) (MigrationSlice, error) {
|
||||
applied, err := m.AppliedMigrations(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existing := migrationMap(m.migrations.ms)
|
||||
for i := len(applied) - 1; i >= 0; i-- {
|
||||
m := &applied[i]
|
||||
if _, ok := existing[m.Name]; ok {
|
||||
applied = append(applied[:i], applied[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return applied, nil
|
||||
}
|
||||
|
||||
// AppliedMigrations selects applied migrations in descending order.
|
||||
func (m *Migrator) AppliedMigrations(ctx context.Context) (MigrationSlice, error) {
|
||||
var ms MigrationSlice
|
||||
if err := m.db.NewSelect().
|
||||
ColumnExpr("*").
|
||||
Model(&ms).
|
||||
ModelTableExpr(m.table).
|
||||
ModelTable(m.distTable(m.migrationsTable)).
|
||||
Final().
|
||||
Scan(ctx); err != nil {
|
||||
return nil, err
|
||||
@@ -330,10 +445,6 @@ func (m *Migrator) selectAppliedMigrations(ctx context.Context) (MigrationSlice,
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
func (m *Migrator) formattedTableName(db *ch.DB) string {
|
||||
return db.Formatter().FormatQuery(m.table)
|
||||
}
|
||||
|
||||
func (m *Migrator) validate() error {
|
||||
if len(m.ms) == 0 {
|
||||
return errors.New("chmigrate: there are no any migrations")
|
||||
@@ -341,6 +452,13 @@ func (m *Migrator) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) distTable(table string) string {
|
||||
if m.distributed {
|
||||
return table + "_dist"
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type migrationLock struct {
|
||||
@@ -351,7 +469,7 @@ func (m *Migrator) Lock(ctx context.Context) error {
|
||||
if _, err := m.db.ExecContext(
|
||||
ctx,
|
||||
"ALTER TABLE ? ADD COLUMN ? Int8",
|
||||
ch.Safe(m.locksTable), ch.Safe("col1"),
|
||||
ch.Safe(m.locksTable), ch.Safe("lock"),
|
||||
); err != nil {
|
||||
return fmt.Errorf("chmigrate: migrations table is already locked (%w)", err)
|
||||
}
|
||||
@@ -362,7 +480,7 @@ func (m *Migrator) Unlock(ctx context.Context) error {
|
||||
if _, err := m.db.ExecContext(
|
||||
ctx,
|
||||
"ALTER TABLE ? DROP COLUMN ?",
|
||||
ch.Safe(m.locksTable), ch.Safe("col1"),
|
||||
ch.Safe(m.locksTable), ch.Safe("lock"),
|
||||
); err != nil && !strings.Contains(err.Error(), "Cannot find column") {
|
||||
return fmt.Errorf("chmigrate: migrations table is already unlocked (%w)", err)
|
||||
}
|
||||
|
@@ -6,17 +6,20 @@ replace github.com/uptrace/go-clickhouse => ./..
|
||||
|
||||
replace github.com/uptrace/go-clickhouse/chdebug => ../chdebug
|
||||
|
||||
exclude go.opentelemetry.io/proto/otlp v0.15.0
|
||||
|
||||
require (
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
go.opentelemetry.io/otel v1.5.0
|
||||
go.opentelemetry.io/otel/trace v1.5.0
|
||||
github.com/uptrace/go-clickhouse v0.3.1
|
||||
go.opentelemetry.io/otel v1.16.0
|
||||
go.opentelemetry.io/otel/trace v1.16.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
)
|
||||
|
@@ -1,35 +1,29 @@
|
||||
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnLTKNzo+bdmT/oH34c2Y=
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.opentelemetry.io/otel v1.5.0 h1:DhCU8oR2sJH9rfnwPdoV/+BJ7UIN5kXHL8DuSGrPU8E=
|
||||
go.opentelemetry.io/otel v1.5.0/go.mod h1:Jm/m+rNp/z0eqJc74H7LPwQ3G87qkU/AnnAydAjSAHk=
|
||||
go.opentelemetry.io/otel/trace v1.5.0 h1:AKQZ9zJsBRFAp7zLdyGNkqG2rToCDIt3i5tcLzQlbmU=
|
||||
go.opentelemetry.io/otel/trace v1.5.0/go.mod h1:sq55kfhjXYr1zVSyexg0w1mpa03AYXR5eyTkB9NPPdE=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 h1:8IVLkfbr2cLhv0a/vKq4UFUcJym8RmDoDboxCFWEjYE=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
|
||||
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@@ -7,17 +7,19 @@ replace github.com/uptrace/go-clickhouse => ../..
|
||||
replace github.com/uptrace/go-clickhouse/chdebug => ../../chdebug
|
||||
|
||||
require (
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.2.0
|
||||
github.com/uptrace/go-clickhouse v0.3.1
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.3.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
||||
|
@@ -2,26 +2,28 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnL
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# go-clickhouse benchmark examples
|
||||
|
||||
These examples allow to compare performance with
|
||||
[clickhouse-go](https://github.com/ClickHouse/clickhouse-go/tree/v2/benchmark/v2).
|
||||
[clickhouse-go](https://github.com/ClickHouse/clickhouse-go/tree/main/benchmark/v2).
|
||||
|
@@ -6,18 +6,13 @@ replace github.com/uptrace/go-clickhouse => ../..
|
||||
|
||||
replace github.com/uptrace/go-clickhouse/chdebug => ../../chdebug
|
||||
|
||||
require (
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.2.0
|
||||
)
|
||||
require github.com/uptrace/go-clickhouse v0.3.1
|
||||
|
||||
require (
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
)
|
||||
|
@@ -2,26 +2,21 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnL
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch"
|
||||
"github.com/uptrace/go-clickhouse/chdebug"
|
||||
)
|
||||
|
||||
const query = `
|
||||
@@ -40,11 +39,10 @@ func benchmark(ctx context.Context, db *ch.DB) error {
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
db := ch.Connect(ch.WithDatabase("test"))
|
||||
db.AddQueryHook(chdebug.NewQueryHook(
|
||||
chdebug.WithEnabled(false),
|
||||
chdebug.FromEnv(""),
|
||||
))
|
||||
db := ch.Connect(
|
||||
ch.WithDatabase("test"),
|
||||
ch.WithCompression(false),
|
||||
)
|
||||
|
||||
start := time.Now()
|
||||
if err := benchmark(ctx, db); err != nil {
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/go-clickhouse/ch"
|
||||
"github.com/uptrace/go-clickhouse/chdebug"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
@@ -35,11 +34,10 @@ func benchmark(ctx context.Context, db *ch.DB) error {
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
db := ch.Connect(ch.WithDatabase("test"))
|
||||
db.AddQueryHook(chdebug.NewQueryHook(
|
||||
chdebug.WithEnabled(false),
|
||||
chdebug.FromEnv(""),
|
||||
))
|
||||
db := ch.Connect(
|
||||
ch.WithDatabase("test"),
|
||||
ch.WithCompression(false),
|
||||
)
|
||||
|
||||
if err := db.ResetModel(ctx, (*Model)(nil)); err != nil {
|
||||
panic(err)
|
||||
|
@@ -36,4 +36,5 @@ To create a SQL migration:
|
||||
go run . db create_sql sql_migration_name
|
||||
```
|
||||
|
||||
See [docs](https://clickhouse.uptrace.dev/guide/migrations.html) for details.
|
||||
See [ClickHouse migrations](https://clickhouse.uptrace.dev/guide/clickhouse-migrations.html) for
|
||||
details.
|
||||
|
@@ -7,20 +7,23 @@ replace github.com/uptrace/go-clickhouse => ../..
|
||||
replace github.com/uptrace/go-clickhouse/chdebug => ../../chdebug
|
||||
|
||||
require (
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.2.0
|
||||
github.com/urfave/cli/v2 v2.4.0
|
||||
github.com/uptrace/go-clickhouse v0.3.1
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.3.1
|
||||
github.com/urfave/cli/v2 v2.25.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
||||
|
@@ -1,36 +1,37 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnLTKNzo+bdmT/oH34c2Y=
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
|
||||
github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc=
|
||||
github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@@ -49,15 +49,23 @@ func newDBCommand(db *ch.DB, migrator *chmigrate.Migrator) *cli.Command {
|
||||
Name: "migrate",
|
||||
Usage: "migrate database",
|
||||
Action: func(c *cli.Context) error {
|
||||
if err := migrator.Lock(c.Context); err != nil {
|
||||
return err
|
||||
}
|
||||
defer migrator.Unlock(c.Context) //nolint:errcheck
|
||||
|
||||
group, err := migrator.Migrate(c.Context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if group.IsZero() {
|
||||
fmt.Printf("there are no new migrations to run (database is up to date)\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("migrated to %s\n", group)
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
@@ -65,15 +73,23 @@ func newDBCommand(db *ch.DB, migrator *chmigrate.Migrator) *cli.Command {
|
||||
Name: "rollback",
|
||||
Usage: "rollback the last migration group",
|
||||
Action: func(c *cli.Context) error {
|
||||
if err := migrator.Lock(c.Context); err != nil {
|
||||
return err
|
||||
}
|
||||
defer migrator.Unlock(c.Context) //nolint:errcheck
|
||||
|
||||
group, err := migrator.Rollback(c.Context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if group.IsZero() {
|
||||
fmt.Printf("there are no groups to roll back\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("rolled back %s\n", group)
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@@ -1,7 +1,10 @@
|
||||
# Example for go-clickhouse OpenTelemetry instrumentation
|
||||
|
||||
See [Performance and errors monitoring](https://clickhouse.uptrace.dev/guide/monitoring.html) for
|
||||
details.
|
||||
To run this example, you need to create `test` ClickHouse database:
|
||||
|
||||
```shell
|
||||
clickhouse-client -q "CREATE DATABASE test"
|
||||
```
|
||||
|
||||
You can run this example with different OpenTelemetry exporters by providing environment variables.
|
||||
|
||||
@@ -23,6 +26,10 @@ OTEL_EXPORTER_JAEGER_ENDPOINT=http://localhost:14268/api/traces go run .
|
||||
UPTRACE_DSN="https://<token>@uptrace.dev/<project_id>" go run .
|
||||
```
|
||||
|
||||
See
|
||||
[Performance and errors monitoring](https://clickhouse.uptrace.dev/guide/clickhouse-monitoring-performance.html)
|
||||
for details.
|
||||
|
||||
## Links
|
||||
|
||||
- [Find instrumentations](https://opentelemetry.uptrace.dev/instrumentations/?lang=go)
|
||||
|
@@ -8,43 +8,46 @@ replace github.com/uptrace/go-clickhouse/chdebug => ../../chdebug
|
||||
|
||||
replace github.com/uptrace/go-clickhouse/chotel => ../../chotel
|
||||
|
||||
exclude go.opentelemetry.io/proto/otlp v0.15.0
|
||||
|
||||
require (
|
||||
github.com/brianvoe/gofakeit/v5 v5.11.2
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
github.com/uptrace/go-clickhouse/chotel v0.2.0
|
||||
github.com/uptrace/opentelemetry-go-extra/otelplay v0.1.10
|
||||
go.opentelemetry.io/otel v1.5.0
|
||||
github.com/uptrace/go-clickhouse v0.3.1
|
||||
github.com/uptrace/go-clickhouse/chotel v0.3.1
|
||||
github.com/uptrace/opentelemetry-go-extra/otelplay v0.2.1
|
||||
go.opentelemetry.io/otel v1.16.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/uptrace/uptrace-go v1.4.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.27.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.27.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.27.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.27.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.5.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
|
||||
google.golang.org/grpc v1.45.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/uptrace/uptrace-go v1.16.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e // indirect
|
||||
google.golang.org/grpc v1.55.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
)
|
||||
|
@@ -1,20 +1,56 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnLTKNzo+bdmT/oH34c2Y=
|
||||
github.com/brianvoe/gofakeit/v5 v5.11.2 h1:Ny5Nsf4z2023ZvYP8ujW8p5B1t5sxhdFaQ/0IYXbeSA=
|
||||
github.com/brianvoe/gofakeit/v5 v5.11.2/go.mod h1:/ZENnKqX+XrN8SORLe/fu5lZDIo1tuPncWuRD+eyhSI=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
@@ -26,20 +62,38 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
@@ -49,154 +103,350 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/uptrace/opentelemetry-go-extra/otelplay v0.1.10 h1:STSRpcp18xb6huePD0yj4uiUFd1cOdb2xexhhPNWwCo=
|
||||
github.com/uptrace/opentelemetry-go-extra/otelplay v0.1.10/go.mod h1:7UDvwITVMKhXZGmxKa/lJujNIOKb5ReIRAVwwrc60bI=
|
||||
github.com/uptrace/uptrace-go v1.4.0 h1:WPYpiCi84nSAXVdtZQamcmDnTZz9724EONo8v1ud9/0=
|
||||
github.com/uptrace/uptrace-go v1.4.0/go.mod h1:KAPqyJuSaRA6YOea6UZEuSeXtWap92Qws9rPYNW8GhU=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.30.0 h1:chMoQpB7M6RQs0DrlblcJ7oC+SuGf9p4O1HfigUiOms=
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.30.0/go.mod h1:qGVpMUNpULYYXRYCQB3DNUe+of22Y+M28i1Oke8SuKQ=
|
||||
go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
|
||||
go.opentelemetry.io/otel v1.5.0 h1:DhCU8oR2sJH9rfnwPdoV/+BJ7UIN5kXHL8DuSGrPU8E=
|
||||
go.opentelemetry.io/otel v1.5.0/go.mod h1:Jm/m+rNp/z0eqJc74H7LPwQ3G87qkU/AnnAydAjSAHk=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.5.0 h1:ZR7nhLSfLufS5AHk/iN11Q+W9XYwsJrVZ1Frb833d+Y=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.5.0/go.mod h1:rSeUArMBRe1eQLo1T0WxOazohN1M2mYThWJQmn1BjRQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.5.0 h1:lC0ldaVQwBpO1G5IaOYRbBCa67h6ioGkK6qYkqZbYOI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.5.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.27.0 h1:t1aPfMj5oZzv2EaRmdC2QPQg1a7MaBjraOh4Hjwuia8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.27.0/go.mod h1:aZnoYVx7GIuMROciGC3cjZhYxMD/lKroRJUnFY0afu0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.27.0 h1:RJURCSrqUjJiCY3GuFCVP2EPKOQLwNXQ4FI3aH2KoHg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.27.0/go.mod h1:LIc1eCpkU94tPnXxH40ya41Oyxm7sL+oDvxCYPFpnV8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.5.0 h1:Arn+HOtC6neocvr6J4ykfILvtiSwoDkkLFMaVLFKBnY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.5.0/go.mod h1:VoN81wyy6jVVCzHImh8S+IYhw+oAUj6XgEsTkP8DyrQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.5.0 h1:dOXExSS490NJaVZD496oIK2Z22S1JQnOsrrMh/p/mLU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.5.0/go.mod h1:Es/Ag4ORtjwWCRjS0aEXgmxB5VqKQlnp481/P5aZyPQ=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.5.0 h1:/Lu2JuL9Mb+B+kSv/RsDMgA/5FaBaxfyfMnICFepiBs=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.5.0/go.mod h1:5gUXICq93HyDh8Rij7p8ilJEC1Sqk0u3lSGs62i8hJQ=
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
|
||||
go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
|
||||
go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ=
|
||||
go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g=
|
||||
go.opentelemetry.io/otel/sdk v1.4.0/go.mod h1:71GJPNJh4Qju6zJuYl1CrYtXbrgfau/M9UAggqiy1UE=
|
||||
go.opentelemetry.io/otel/sdk v1.5.0 h1:QKhWBbcOC9fDCZKCfPFjWTWpfIlJR+i9xiUDYrLVmZs=
|
||||
go.opentelemetry.io/otel/sdk v1.5.0/go.mod h1:CU4J1v+7iEljnm1G14QjdFWOXUyYLHVh0Lh+/BTYyFg=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.27.0 h1:CDEu96Js5IP7f4bJ8eimxF09V5hKYmE7CeyKSjmAL1s=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.27.0/go.mod h1:lOgrT5C3ORdbqp2LsDrx+pBj6gbZtQ5Omk27vH3EaW0=
|
||||
go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
|
||||
go.opentelemetry.io/otel/trace v1.5.0 h1:AKQZ9zJsBRFAp7zLdyGNkqG2rToCDIt3i5tcLzQlbmU=
|
||||
go.opentelemetry.io/otel/trace v1.5.0/go.mod h1:sq55kfhjXYr1zVSyexg0w1mpa03AYXR5eyTkB9NPPdE=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/uptrace/opentelemetry-go-extra/otelplay v0.2.1 h1:HOqi3aZ4VnduY66JatQnejArkmSlHOdksSezbJQ2Kx0=
|
||||
github.com/uptrace/opentelemetry-go-extra/otelplay v0.2.1/go.mod h1:VkRwJRe6BQeaX9FhNKil09LQSazSeC9NYz+P//Rhr2E=
|
||||
github.com/uptrace/uptrace-go v1.16.0 h1:yB9vt1hBYYoXWExNx0okubLOjd339d7lH+/5o+Lp+MY=
|
||||
github.com/uptrace/uptrace-go v1.16.0/go.mod h1:Ssc5wLpoL+9V0qkT5FtrIiru9SY4xb7q1UVLjSpxpCg=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.42.0 h1:EbmAUG9hEAMXyfWEasIt2kmh/WmXUznUksChApTgBGc=
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.42.0/go.mod h1:rD9feqRYP24P14t5kmhNMqsqm1jvKmpx2H2rKVw52V8=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.16.0 h1:YhxxmXZ011C0aDZKoNw+juVWAmEfv/0W2XBOv9aHTaA=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.16.0/go.mod h1:grYbBo/5afWlPpdPZYhyn78Bk04hnvxn2+hvxQhKIQM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 h1:f6BwB2OACc3FCbYVznctQ9V6KK7Vq6CjmYXJ7DeSs4E=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0/go.mod h1:UqL5mZ3qs6XYhDnZaW1Ps4upD+PX6LipH40AoeuIlwU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0 h1:rm+Fizi7lTM2UefJ1TO347fSRcwmIsUAaZmYmIGBRAo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0/go.mod h1:sWFbI3jJ+6JdjOVepA5blpv/TJ20Hw+26561iMbWcwU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc=
|
||||
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
|
||||
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
|
||||
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
|
||||
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c=
|
||||
go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
|
||||
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg=
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw=
|
||||
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e h1:AZX1ra8YbFMSb7+1pI8S9v4rrgRR7jU1FmuFSSjTVcQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e h1:NumxXLPfHSndr3wBBdeKiVHjGVFzi9RX2HwwQke94iY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -205,16 +455,27 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
@@ -6,4 +6,6 @@ To run this example:
|
||||
go run .
|
||||
```
|
||||
|
||||
See [docs](https://clickhouse.uptrace.dev/guide/placeholders.html) for details.
|
||||
See
|
||||
[ClickHouse SQL placeholders](https://clickhouse.uptrace.dev/guide/clickhouse-sql-placeholders.html)
|
||||
for details.
|
||||
|
@@ -7,17 +7,19 @@ replace github.com/uptrace/go-clickhouse => ../..
|
||||
replace github.com/uptrace/go-clickhouse/chdebug => ../../chdebug
|
||||
|
||||
require (
|
||||
github.com/uptrace/go-clickhouse v0.2.0
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.2.0
|
||||
github.com/uptrace/go-clickhouse v0.3.1
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.3.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/codemodus/kace v0.5.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
||||
|
@@ -2,26 +2,28 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnL
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
20
go.mod
20
go.mod
@@ -8,20 +8,22 @@ require (
|
||||
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible
|
||||
github.com/codemodus/kace v0.5.1
|
||||
github.com/jinzhu/inflection v1.0.0
|
||||
github.com/pierrec/lz4/v4 v4.1.14
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.0.0-00010101000000-000000000000
|
||||
golang.org/x/exp v0.0.0-20220307200941-a1099baf94bf
|
||||
github.com/pierrec/lz4/v4 v4.1.17
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/uptrace/go-clickhouse/chdebug v0.3.1
|
||||
go.opentelemetry.io/otel/trace v1.16.0
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
49
go.sum
49
go.sum
@@ -2,11 +2,11 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnL
|
||||
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible/go.mod h1:Au1Xw1sgaJ5iSFktEhYsS0dbQiS1B0/XMXl+42y9Ilk=
|
||||
github.com/codemodus/kace v0.5.1 h1:4OCsBlE2c/rSJo375ggfnucv9eRzge/U5LrrOZd47HA=
|
||||
github.com/codemodus/kace v0.5.1/go.mod h1:coddaHoX1ku1YFSe4Ip0mL9kQjJvKkzb9CfIdG1YR04=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -14,30 +14,29 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/exp v0.0.0-20220307200941-a1099baf94bf h1:IoCgLaQjznvljAcEatPiHdqZi9oIBU5w0AJrlRkzX7s=
|
||||
golang.org/x/exp v0.0.0-20220307200941-a1099baf94bf/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 h1:8IVLkfbr2cLhv0a/vKq4UFUcJym8RmDoDboxCFWEjYE=
|
||||
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uptrace/go-clickhouse",
|
||||
"version": "0.2.0",
|
||||
"name": "goclickhouse",
|
||||
"version": "0.3.1",
|
||||
"main": "index.js",
|
||||
"repository": "git@github.com:uptrace/go-clickhouse.git",
|
||||
"author": "Vladimir Mihailenco <vladimir.webdev@gmail.com>",
|
||||
|
@@ -41,24 +41,22 @@ fi
|
||||
|
||||
git checkout master
|
||||
|
||||
PACKAGE_DIRS=$(find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; \
|
||||
PACKAGE_DIRS=$(find . -mindepth 1 -type f -name 'go.mod' -exec dirname {} \; \
|
||||
| sed 's/^\.\///' \
|
||||
| sort)
|
||||
|
||||
for dir in $PACKAGE_DIRS
|
||||
do
|
||||
printf "${dir}: go get -u && go mod tidy\n"
|
||||
(cd ./${dir} && go get -u && go mod tidy)
|
||||
printf "${dir}: go get -u && go mod tidy -compat=1.18\n"
|
||||
(cd ${dir} && go mod tidy -compat=1.18)
|
||||
done
|
||||
|
||||
for dir in $PACKAGE_DIRS
|
||||
do
|
||||
sed --in-place \
|
||||
"s/uptrace\/go-clickhouse\([^ ]*\) v.*/uptrace\/go-clickhouse\1 ${TAG}/" "${dir}/go.mod"
|
||||
(cd ./${dir} && go mod tidy)
|
||||
done
|
||||
|
||||
|
||||
sed --in-place "s/\(return \)\"[^\"]*\"/\1\"${TAG#v}\"/" ./version.go
|
||||
sed --in-place "s/\(\"version\": \)\"[^\"]*\"/\1\"${TAG#v}\"/" ./package.json
|
||||
|
||||
|
@@ -2,5 +2,5 @@ package clickhouse
|
||||
|
||||
// Version is the current release version.
|
||||
func Version() string {
|
||||
return "0.2.0"
|
||||
return "0.3.1"
|
||||
}
|
||||
|
Reference in New Issue
Block a user