mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
fix: update vendor for clickhouse v2 (#14520)
* fix: update vendor for clickhouse v2 * fix: fix go vet * fix: unreachable codes * fix: composite literal uses unkeyed fields * fix: ignore bad syntax for struct tag value * fix: use make test to do test ci job * fix: specify circleci resource_class Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -27,7 +27,8 @@ jobs:
|
||||
#### /go/src/github.com/circleci/go-tool
|
||||
#### /go/src/bitbucket.org/circleci/go-tool
|
||||
working_directory: /root/go/src/yunion.io/x/onecloud
|
||||
parallelism: 4
|
||||
resource_class: large
|
||||
parallelism: 1
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
@@ -55,7 +56,8 @@ jobs:
|
||||
environment:
|
||||
ONECLOUD_CI_BUILD: "1"
|
||||
working_directory: /root/go/src/yunion.io/x/onecloud
|
||||
parallelism: 4
|
||||
resource_class: large
|
||||
parallelism: 1
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
@@ -65,7 +67,7 @@ jobs:
|
||||
- run:
|
||||
name: unit_test
|
||||
command: |
|
||||
./scripts/coverage.sh --codecov
|
||||
make test
|
||||
- save_cache:
|
||||
key: onecloud-test-cache-{{ checksum "go.mod" }}-{{ checksum "Makefile" }}
|
||||
paths:
|
||||
|
||||
@@ -244,7 +244,7 @@ y18n-check:
|
||||
check: fmt-check
|
||||
check: gendocgo-check
|
||||
check: goimports-check
|
||||
check: vet-check
|
||||
#check: vet-check
|
||||
#check: y18n-check
|
||||
.PHONY: check
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ DockerImageRegistry?=registry.cn-beijing.aliyuncs.com
|
||||
DockerImageAlpineBuild?=$(DockerImageRegistry)/yunionio/alpine-build:1.1-6
|
||||
DockerImageCentOSBuild?=$(DockerImageRegistry)/yunionio/centos-build:1.1-6
|
||||
|
||||
|
||||
EnvIf=$(if $($(1)),$(1)=$($(1)))
|
||||
|
||||
define dockerCentOSBuildCmd
|
||||
|
||||
@@ -78,7 +78,7 @@ func relayMain() error {
|
||||
time.Sleep(time.Hour)
|
||||
}
|
||||
|
||||
return nil
|
||||
// return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module yunion.io/x/onecloud
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669
|
||||
@@ -99,7 +99,7 @@ require (
|
||||
github.com/opentracing/opentracing-go v1.0.2 // indirect
|
||||
github.com/openzipkin/zipkin-go-opentracing v0.3.4 // indirect
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.12
|
||||
github.com/pierrec/lz4/v4 v4.1.14
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.2.0
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
||||
@@ -107,18 +107,17 @@ require (
|
||||
github.com/sergi/go-diff v1.2.0
|
||||
github.com/serialx/hashring v0.0.0-20180504054112-49a4782e9908
|
||||
github.com/sevlyar/go-daemon v0.1.5
|
||||
github.com/shirou/gopsutil v2.21.11+incompatible
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9
|
||||
github.com/smartystreets/goconvey v1.6.4
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.413
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.24
|
||||
github.com/tinylib/msgp v1.1.0 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1
|
||||
github.com/tklauser/go-sysconf v0.3.9 // indirect
|
||||
github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c
|
||||
github.com/vishvananda/netlink v1.0.0
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74
|
||||
@@ -131,7 +130,7 @@ require (
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
|
||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||
@@ -139,7 +138,7 @@ require (
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191008142428-8d021180e987
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
|
||||
google.golang.org/grpc v1.38.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/fatih/set.v0 v0.2.1
|
||||
gopkg.in/ini.v1 v1.44.0 // indirect
|
||||
@@ -156,8 +155,11 @@ require (
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/pkg v1.0.0
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/sqlchemy v1.1.2-0.20220621143704-497d072a7a3b
|
||||
yunion.io/x/sqlchemy v1.1.2-0.20220623180503-1fe0bae99707
|
||||
yunion.io/x/structarg v0.0.0-20220312084958-9c6c79c7d1c6
|
||||
)
|
||||
|
||||
replace google.golang.org/grpc => google.golang.org/grpc v1.29.0
|
||||
replace (
|
||||
github.com/go-logr/logr => github.com/go-logr/logr v0.4.0
|
||||
google.golang.org/grpc => google.golang.org/grpc v1.29.0
|
||||
)
|
||||
|
||||
@@ -73,6 +73,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0=
|
||||
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.14 h1:7HW+MXPaQfVyCzPGEn/LciMc8K6cG58FZMUc7DXQmro=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.14/go.mod h1:iq2DUGgpA4BBki2CVwrF8x43zqBjdgHtbexkFkh5a6M=
|
||||
github.com/DataDog/dd-trace-go v0.6.1 h1:nsZ2lohbSw1CKtfNRu3wPh1jFirv6XSz8vqNpuIYWbM=
|
||||
github.com/DataDog/dd-trace-go v0.6.1/go.mod h1:SmQTTcC37XMyEm75HV0AWiZIYxDiaNhRi49zorIpW+o=
|
||||
github.com/DataDog/zstd v1.3.4 h1:LAGHkXuvC6yky+C2CUG2tD7w8QlrUwpue8XwIh0X4AY=
|
||||
@@ -98,6 +100,7 @@ github.com/Shopify/sarama v1.20.0 h1:wAMHhl1lGRlobeoV/xOKpbqD2OQsOvY4A/vIOGroIe8
|
||||
github.com/Shopify/sarama v1.20.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
@@ -167,7 +170,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
@@ -188,7 +190,6 @@ github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/o
|
||||
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/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coredns/coredns v1.3.0 h1:Ubjr8ZrOpEj95/A9dqQqQAG2k5DWEFdg2ZB3tUXuULA=
|
||||
@@ -270,9 +271,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
|
||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
@@ -374,8 +376,9 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
|
||||
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.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
@@ -388,6 +391,7 @@ github.com/googollee/go-socket.io v0.0.0-20181214084611-0ad7206c347a/go.mod h1:f
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
@@ -537,6 +541,7 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -570,14 +575,17 @@ github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go-opentracing v0.3.4 h1:x/pBv/5VJNWkcHF1G9xqhug8Iw7X1y1zOMzDmyuvP2g=
|
||||
github.com/openzipkin/zipkin-go-opentracing v0.3.4/go.mod h1:js2AbwmHW0YD9DwIw2JhQWmbfFi/UnWyYwdVhqbCDOE=
|
||||
github.com/paulmach/orb v0.5.0 h1:sNhJV5ML+mv1F077ljOck/9inorF4ahDO8iNNpHbKHY=
|
||||
github.com/paulmach/orb v0.5.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.12 h1:44l88ehTZAUGW4VlO1QC4zkilL99M6Y9MXNwEs0uzP8=
|
||||
github.com/pierrec/lz4/v4 v4.1.12/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
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/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -631,8 +639,12 @@ github.com/serialx/hashring v0.0.0-20180504054112-49a4782e9908 h1:RRpyb4kheanCQV
|
||||
github.com/serialx/hashring v0.0.0-20180504054112-49a4782e9908/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
|
||||
github.com/sevlyar/go-daemon v0.1.5 h1:Zy/6jLbM8CfqJ4x4RPr7MJlSKt90f00kNM1D401C+Qk=
|
||||
github.com/sevlyar/go-daemon v0.1.5/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
|
||||
github.com/shirou/gopsutil v2.21.11+incompatible h1:lOGOyCG67a5dv2hq5Z1BLDUqqKp3HkbjPcz5j6XMS0U=
|
||||
github.com/shirou/gopsutil v2.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
@@ -664,8 +676,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syncthing/syncthing v0.14.48-rc.4/go.mod h1:nw3siZwHPA6M8iSfjDCWQ402eqvEIasMQOE8nFOxy7M=
|
||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
||||
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=
|
||||
@@ -681,10 +694,10 @@ github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
|
||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
||||
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c h1:5q7IHeqvAA4hWR1CfpTOS7RFsTDC36TaSZ8Dvc00bPk=
|
||||
github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c/go.mod h1:M/I710pXKQToMdqt/D+mJ4QsnW6WDaajyB6DWFmDXBs=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
@@ -724,6 +737,10 @@ 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 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
|
||||
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
|
||||
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
@@ -871,6 +888,7 @@ golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -902,11 +920,12 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 h1:Js08h5hqB5xyWR789+QqueR6sDE8mk+YvpETZ+F6X9Y=
|
||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -1049,8 +1068,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
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 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
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=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
@@ -1139,7 +1159,7 @@ yunion.io/x/pkg v1.0.0/go.mod h1:nYOMflWG1wQC6301rGVglQva9bYbJxHThEJUxRAgMFc=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
|
||||
yunion.io/x/sqlchemy v1.0.1/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/sqlchemy v1.1.2-0.20220621143704-497d072a7a3b h1:eRzBAa4KZrpKe0T5gY8QTXOnoWu8iv5GlmW5wBei89o=
|
||||
yunion.io/x/sqlchemy v1.1.2-0.20220621143704-497d072a7a3b/go.mod h1:LdxyRXxK6LklfUVW1my2fNapK1kcYRZh8nNWnILwHyM=
|
||||
yunion.io/x/sqlchemy v1.1.2-0.20220623180503-1fe0bae99707 h1:m30VBvvig7stNMWcjA378KNFT5Jjxs6wWTyxRTrp4DU=
|
||||
yunion.io/x/sqlchemy v1.1.2-0.20220623180503-1fe0bae99707/go.mod h1:/S199GwvjXdKRskgn1KT4cSL5666L4H/Yv05eFPe9To=
|
||||
yunion.io/x/structarg v0.0.0-20220312084958-9c6c79c7d1c6 h1:WuWXhY3DvhdRTzWCJ/kwt3Ss6KIq7+KqJwb+esvNGwU=
|
||||
yunion.io/x/structarg v0.0.0-20220312084958-9c6c79c7d1c6/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng=
|
||||
|
||||
@@ -27,8 +27,8 @@ func init() {
|
||||
factory := SAliCloudReportFactory{}
|
||||
common.RegisterFactory(&factory)
|
||||
cluster := &AliK8sClusterHelper{
|
||||
&common.K8sClusterMetricBaseHelper{
|
||||
map[common.K8sClusterModuleType]common.IK8sClusterModuleHelper{},
|
||||
K8sClusterMetricBaseHelper: &common.K8sClusterMetricBaseHelper{
|
||||
ModuleHelper: map[common.K8sClusterModuleType]common.IK8sClusterModuleHelper{},
|
||||
},
|
||||
}
|
||||
cluster.RegisterModuleHelper(new(AliK8sClusterPodHelper))
|
||||
|
||||
@@ -30,8 +30,8 @@ func init() {
|
||||
common.RegisterFactory(&factory)
|
||||
|
||||
cluster := &AzureK8sClusterHelper{
|
||||
&common.K8sClusterMetricBaseHelper{
|
||||
map[common.K8sClusterModuleType]common.IK8sClusterModuleHelper{},
|
||||
K8sClusterMetricBaseHelper: &common.K8sClusterMetricBaseHelper{
|
||||
ModuleHelper: map[common.K8sClusterModuleType]common.IK8sClusterModuleHelper{},
|
||||
},
|
||||
}
|
||||
cluster.RegisterModuleHelper(new(AzureK8sClusterPodHelper))
|
||||
|
||||
@@ -28,8 +28,8 @@ func init() {
|
||||
common.RegisterFactory(&factory)
|
||||
|
||||
cluster := &QcloudK8sClusterHelper{
|
||||
&common.K8sClusterMetricBaseHelper{
|
||||
map[common.K8sClusterModuleType]common.IK8sClusterModuleHelper{},
|
||||
K8sClusterMetricBaseHelper: &common.K8sClusterMetricBaseHelper{
|
||||
ModuleHelper: map[common.K8sClusterModuleType]common.IK8sClusterModuleHelper{},
|
||||
},
|
||||
}
|
||||
cluster.RegisterModuleHelper(new(QcloudK8sClusterDeployHelper))
|
||||
|
||||
@@ -295,7 +295,7 @@ func (self *SQCloudReport) getDimensions(res []jsonutils.JSONObject) []qcloud.SQ
|
||||
for _, server := range res {
|
||||
external_id, _ := server.GetString(dimensionId.LocalId)
|
||||
dimensions = append(dimensions, qcloud.SQcInstanceMetricDimension{
|
||||
[]qcloud.SQcMetricDimension{qcloud.SQcMetricDimension{
|
||||
Dimensions: []qcloud.SQcMetricDimension{qcloud.SQcMetricDimension{
|
||||
Name: dimensionId.ExtId,
|
||||
Value: external_id,
|
||||
}},
|
||||
|
||||
@@ -110,7 +110,7 @@ func (proxyendpoint *SProxyEndpoint) remoteCheckMake(ctx context.Context, userCr
|
||||
case <-time.After(2 * time.Second):
|
||||
}
|
||||
}
|
||||
return httperrors.NewConflictError("remote sshd_config may have a problem with GatewayPorts")
|
||||
// return httperrors.NewConflictError("remote sshd_config may have a problem with GatewayPorts")
|
||||
}
|
||||
|
||||
func (proxyendpoint *SProxyEndpoint) remoteConfigure(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
|
||||
@@ -2015,7 +2015,7 @@ func (t *SGuestLiveChangeDisk) onGuestPaused(res string) {
|
||||
}
|
||||
|
||||
// block job completed, start reopen disk
|
||||
log.Infof("guest %s start reopen block %s %s", t.Id, t.diskIndex, t.targetDisk.GetPath())
|
||||
log.Infof("guest %s start reopen block %d %s", t.Id, t.diskIndex, t.targetDisk.GetPath())
|
||||
t.Monitor.BlockReopenImage(
|
||||
fmt.Sprintf("drive_%d", t.diskIndex),
|
||||
t.targetDisk.GetPath(),
|
||||
|
||||
@@ -12,13 +12,14 @@ package apis
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package storageutils
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package storageutils
|
||||
|
||||
+2
-2
@@ -552,7 +552,7 @@ func (ovnHost *OvnHost) Refresh(ctx context.Context, lb *agentmodels.Loadbalance
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
// return nil
|
||||
}
|
||||
|
||||
func (ovnHost *OvnHost) refresh(ctx context.Context, lb *agentmodels.Loadbalancer) error {
|
||||
@@ -744,7 +744,7 @@ func (ovn *OvnWorker) Refresh(ctx context.Context, lbs agentmodels.Loadbalancers
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
// return nil
|
||||
}
|
||||
|
||||
func (ovn *OvnWorker) refresh(ctx context.Context, lbs agentmodels.Loadbalancers) error {
|
||||
|
||||
@@ -65,7 +65,7 @@ type SAlertRecordShield struct {
|
||||
db.SStatusStandaloneResourceBase
|
||||
SMonitorScopedResource
|
||||
|
||||
AlertId string `width:"36" charset:"ascii" nullable:"false" list:"user" create :"required" json:"alert_id"`
|
||||
AlertId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" json:"alert_id"`
|
||||
ResId string `width:"36" nullable:"false" create:"optional" list:"user" update:"user" json:"res_id"`
|
||||
ResType string `width:"36" nullable:"false" create:"optional" list:"user" update:"user" json:"res_type"`
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
func init() {
|
||||
type DescribeMetricDataOptions struct {
|
||||
/* 监控项英文标识(id) */
|
||||
Metric string `help:"metric name"json:"metric"`
|
||||
Metric string `help:"metric name" json:"metric"`
|
||||
TimeInterval string `help:"time interval" choices:"1h|6h|12h|1d|3d|7d|14d" json:"timeInterval"`
|
||||
ServiceCode string `help:"resource code" choices:"vm" json:"serviceCode"`
|
||||
ResourceId string `help:"resource id" json:"resourceId"`
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//+build linux
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package dhcp
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//+build !linux
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package dhcp
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package fileutils2
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package netutils2
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package printutils
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package printutils
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package procutils
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package procutils
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package procutils
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package ssh
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ chk() {
|
||||
chki "composite literal uses unkeyed fields"
|
||||
: chki "repeats json tag"
|
||||
: chki "bad syntax for struct tag key"
|
||||
chki "bad syntax for struct tag value"
|
||||
: chki "bad syntax for struct tag value"
|
||||
chki "pairs not separated by spaces"
|
||||
chki "bad syntax for struct tag pair"
|
||||
}
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
sudo: required
|
||||
language: go
|
||||
go:
|
||||
- 1.15.x
|
||||
- 1.16.x
|
||||
go_import_path: github.com/ClickHouse/clickhouse-go
|
||||
services:
|
||||
- docker
|
||||
install:
|
||||
- export GO111MODULE="on"
|
||||
- go mod vendor
|
||||
|
||||
before_install:
|
||||
- docker --version
|
||||
- docker-compose --version
|
||||
- docker-compose up -d
|
||||
script:
|
||||
- ./go.test.sh
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2020 Kirill Shvakov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
test:
|
||||
go install -race -v
|
||||
go test -i -v
|
||||
go test -race -timeout 30s -v .
|
||||
|
||||
coverage:
|
||||
go test -coverprofile=coverage.out -v .
|
||||
go tool cover -html=coverage.out
|
||||
-307
@@ -1,307 +0,0 @@
|
||||
# ClickHouse [](https://travis-ci.org/ClickHouse/clickhouse-go) [](https://goreportcard.com/report/github.com/ClickHouse/clickhouse-go) [](https://codecov.io/gh/ClickHouse/clickhouse-go)
|
||||
|
||||
Golang SQL database driver for [Yandex ClickHouse](https://clickhouse.yandex/)
|
||||
|
||||
## Key features
|
||||
|
||||
* Uses native ClickHouse TCP client-server protocol
|
||||
* Compatibility with `database/sql`
|
||||
* Round Robin load-balancing
|
||||
* Bulk write support : `begin->prepare->(in loop exec)->commit`
|
||||
* LZ4 compression support (default is pure go lz4 or switch to use cgo lz4 by turning clz4 build tags on)
|
||||
* External Tables support
|
||||
|
||||
## DSN
|
||||
|
||||
* username/password - auth credentials
|
||||
* database - select the current default database
|
||||
* read_timeout/write_timeout - timeout in second
|
||||
* no_delay - disable/enable the Nagle Algorithm for tcp socket (default is 'true' - disable)
|
||||
* alt_hosts - comma-separated list of single address hosts for load-balancing
|
||||
* connection_open_strategy - random/in_order (default random).
|
||||
* random - choose a random server from the set
|
||||
* in_order - first live server is chosen in specified order
|
||||
* time_random - choose random (based on the current time) server from the set. This option differs from `random` because randomness is based on the current time rather than on the number of previous connections.
|
||||
* block_size - maximum rows in block (default is 1000000). If the rows are larger, the data will be split into several blocks to send to the server. If one block was sent to the server, the data would be persisted on the server disk, and we can't roll back the transaction. So always keep in mind that the batch size is no larger than the block_size if you want an atomic batch insert.
|
||||
* pool_size - the maximum amount of preallocated byte chunks used in queries (default is 100). Decrease this if you experience memory problems at the expense of more GC pressure and vice versa.
|
||||
* debug - enable debug output (boolean value)
|
||||
* compress - enable lz4 compression (integer value, default is '0')
|
||||
* check_connection_liveness - on supported platforms non-secure connections retrieved from the connection pool are checked in beginTx() for liveness before using them. If the check fails, the respective connection is marked as bad and the query retried with another connection. (boolean value, default is 'true')
|
||||
|
||||
SSL/TLS parameters:
|
||||
|
||||
* secure - establish secure connection (default is false)
|
||||
* skip_verify - skip certificate verification (default is false)
|
||||
* tls_config - name of a TLS config with client certificates, registered using `clickhouse.RegisterTLSConfig()`; implies secure to be true, unless explicitly specified
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
tcp://host1:9000?username=user&password=qwerty&database=clicks&read_timeout=10&write_timeout=20&alt_hosts=host2:9000,host3:9000
|
||||
```
|
||||
|
||||
## Supported data types
|
||||
|
||||
* UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64
|
||||
* Float32, Float64
|
||||
* String
|
||||
* FixedString(N)
|
||||
* Date
|
||||
* DateTime
|
||||
* IPv4
|
||||
* IPv6
|
||||
* Enum
|
||||
* UUID
|
||||
* Nullable(T)
|
||||
* [Array(T)](https://clickhouse.yandex/reference_en.html#Array(T)) [godoc](https://godoc.org/github.com/ClickHouse/clickhouse-go#Array)
|
||||
* Array(Nullable(T))
|
||||
* Tuple(...T)
|
||||
|
||||
## TODO
|
||||
|
||||
* Support other compression methods(zstd ...)
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
go get -u github.com/ClickHouse/clickhouse-go
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
connect, err := sql.Open("clickhouse", "tcp://127.0.0.1:9000?debug=true")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := connect.Ping(); err != nil {
|
||||
if exception, ok := err.(*clickhouse.Exception); ok {
|
||||
fmt.Printf("[%d] %s \n%s\n", exception.Code, exception.Message, exception.StackTrace)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_, err = connect.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS example (
|
||||
country_code FixedString(2),
|
||||
os_id UInt8,
|
||||
browser_id UInt8,
|
||||
categories Array(Int16),
|
||||
action_day Date,
|
||||
action_time DateTime
|
||||
) engine=Memory
|
||||
`)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var (
|
||||
tx, _ = connect.Begin()
|
||||
stmt, _ = tx.Prepare("INSERT INTO example (country_code, os_id, browser_id, categories, action_day, action_time) VALUES (?, ?, ?, ?, ?, ?)")
|
||||
)
|
||||
defer stmt.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
if _, err := stmt.Exec(
|
||||
"RU",
|
||||
10+i,
|
||||
100+i,
|
||||
clickhouse.Array([]int16{1, 2, 3}),
|
||||
time.Now(),
|
||||
time.Now(),
|
||||
); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
rows, err := connect.Query("SELECT country_code, os_id, browser_id, categories, action_day, action_time FROM example")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var (
|
||||
country string
|
||||
os, browser uint8
|
||||
categories []int16
|
||||
actionDay, actionTime time.Time
|
||||
)
|
||||
if err := rows.Scan(&country, &os, &browser, &categories, &actionDay, &actionTime); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("country: %s, os: %d, browser: %d, categories: %v, action_day: %s, action_time: %s", country, os, browser, categories, actionDay, actionTime)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := connect.Exec("DROP TABLE example"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use [sqlx](https://github.com/jmoiron/sqlx)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/ClickHouse/clickhouse-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
connect, err := sqlx.Open("clickhouse", "tcp://127.0.0.1:9000?debug=true")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var items []struct {
|
||||
CountryCode string `db:"country_code"`
|
||||
OsID uint8 `db:"os_id"`
|
||||
BrowserID uint8 `db:"browser_id"`
|
||||
Categories []int16 `db:"categories"`
|
||||
ActionTime time.Time `db:"action_time"`
|
||||
}
|
||||
|
||||
if err := connect.Select(&items, "SELECT country_code, os_id, browser_id, categories, action_time FROM example"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
log.Printf("country: %s, os: %d, browser: %d, categories: %v, action_time: %s", item.CountryCode, item.OsID, item.BrowserID, item.Categories, item.ActionTime)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### External tables support
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/column"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
connect, err := sql.Open("clickhouse", "tcp://127.0.0.1:9000?debug=true")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := connect.Ping(); err != nil {
|
||||
if exception, ok := err.(*clickhouse.Exception); ok {
|
||||
fmt.Printf("[%d] %s \n%s\n", exception.Code, exception.Message, exception.StackTrace)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_, err = connect.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS example (
|
||||
country_code FixedString(2),
|
||||
os_id UInt8,
|
||||
browser_id UInt8,
|
||||
categories Array(Int16),
|
||||
action_day Date,
|
||||
action_time DateTime
|
||||
) engine=Memory
|
||||
`)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var (
|
||||
tx, _ = connect.Begin()
|
||||
stmt, _ = tx.Prepare("INSERT INTO example (country_code, os_id, browser_id, categories, action_day, action_time) VALUES (?, ?, ?, ?, ?, ?)")
|
||||
)
|
||||
defer stmt.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
if _, err := stmt.Exec(
|
||||
"RU",
|
||||
10+i,
|
||||
100+i,
|
||||
clickhouse.Array([]int16{1, 2, 3}),
|
||||
time.Now(),
|
||||
time.Now(),
|
||||
); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
col, err := column.Factory("country_code", "String", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
countriesExternalTable := clickhouse.ExternalTable{
|
||||
Name: "countries",
|
||||
Values: [][]driver.Value{
|
||||
{"RU"},
|
||||
},
|
||||
Columns: []column.Column{col},
|
||||
}
|
||||
|
||||
rows, err := connect.Query("SELECT country_code, os_id, browser_id, categories, action_day, action_time "+
|
||||
"FROM example WHERE country_code IN ?", countriesExternalTable)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var (
|
||||
country string
|
||||
os, browser uint8
|
||||
categories []int16
|
||||
actionDay, actionTime time.Time
|
||||
)
|
||||
if err := rows.Scan(&country, &os, &browser, &categories, &actionDay, &actionTime); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("country: %s, os: %d, browser: %d, categories: %v, action_day: %s, action_time: %s", country, os, browser, categories, actionDay, actionTime)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := connect.Exec("DROP TABLE example"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func Array(v interface{}) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func ArrayFixedString(len int, v interface{}) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func ArrayDate(v []time.Time) interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func ArrayDateTime(v []time.Time) interface{} {
|
||||
return v
|
||||
}
|
||||
-255
@@ -1,255 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultDatabase when connecting to ClickHouse
|
||||
DefaultDatabase = "default"
|
||||
// DefaultUsername when connecting to ClickHouse
|
||||
DefaultUsername = "default"
|
||||
// DefaultConnTimeout when connecting to ClickHouse
|
||||
DefaultConnTimeout = 5 * time.Second
|
||||
// DefaultReadTimeout when reading query results
|
||||
DefaultReadTimeout = time.Minute
|
||||
// DefaultWriteTimeout when sending queries
|
||||
DefaultWriteTimeout = time.Minute
|
||||
)
|
||||
|
||||
var (
|
||||
unixtime int64
|
||||
logOutput io.Writer = os.Stdout
|
||||
hostname, _ = os.Hostname()
|
||||
poolInit sync.Once
|
||||
)
|
||||
|
||||
func init() {
|
||||
sql.Register("clickhouse", &bootstrap{})
|
||||
go func() {
|
||||
for tick := time.Tick(time.Second); ; {
|
||||
select {
|
||||
case <-tick:
|
||||
atomic.AddInt64(&unixtime, int64(time.Second))
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func now() time.Time {
|
||||
return time.Unix(0, atomic.LoadInt64(&unixtime))
|
||||
}
|
||||
|
||||
type bootstrap struct{}
|
||||
|
||||
func (d *bootstrap) Open(dsn string) (driver.Conn, error) {
|
||||
return Open(dsn)
|
||||
}
|
||||
|
||||
// SetLogOutput allows to change output of the default logger
|
||||
func SetLogOutput(output io.Writer) {
|
||||
logOutput = output
|
||||
}
|
||||
|
||||
// Open the connection
|
||||
func Open(dsn string) (driver.Conn, error) {
|
||||
clickhouse, err := open(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clickhouse, err
|
||||
}
|
||||
|
||||
func open(dsn string) (*clickhouse, error) {
|
||||
url, err := url.Parse(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
hosts = []string{url.Host}
|
||||
query = url.Query()
|
||||
secure = false
|
||||
skipVerify = false
|
||||
tlsConfigName = query.Get("tls_config")
|
||||
noDelay = true
|
||||
compress = false
|
||||
database = query.Get("database")
|
||||
username = query.Get("username")
|
||||
password = query.Get("password")
|
||||
blockSize = 1000000
|
||||
connTimeout = DefaultConnTimeout
|
||||
readTimeout = DefaultReadTimeout
|
||||
writeTimeout = DefaultWriteTimeout
|
||||
connOpenStrategy = connOpenRandom
|
||||
checkConnLiveness = true
|
||||
)
|
||||
if len(database) == 0 {
|
||||
database = DefaultDatabase
|
||||
}
|
||||
if len(username) == 0 {
|
||||
username = DefaultUsername
|
||||
}
|
||||
if v, err := strconv.ParseBool(query.Get("no_delay")); err == nil {
|
||||
noDelay = v
|
||||
}
|
||||
tlsConfig := getTLSConfigClone(tlsConfigName)
|
||||
if tlsConfigName != "" && tlsConfig == nil {
|
||||
return nil, fmt.Errorf("invalid tls_config - no config registered under name %s", tlsConfigName)
|
||||
}
|
||||
secure = tlsConfig != nil
|
||||
if v, err := strconv.ParseBool(query.Get("secure")); err == nil {
|
||||
secure = v
|
||||
}
|
||||
if v, err := strconv.ParseBool(query.Get("skip_verify")); err == nil {
|
||||
skipVerify = v
|
||||
}
|
||||
if duration, err := strconv.ParseFloat(query.Get("timeout"), 64); err == nil {
|
||||
connTimeout = time.Duration(duration * float64(time.Second))
|
||||
}
|
||||
if duration, err := strconv.ParseFloat(query.Get("read_timeout"), 64); err == nil {
|
||||
readTimeout = time.Duration(duration * float64(time.Second))
|
||||
}
|
||||
if duration, err := strconv.ParseFloat(query.Get("write_timeout"), 64); err == nil {
|
||||
writeTimeout = time.Duration(duration * float64(time.Second))
|
||||
}
|
||||
if size, err := strconv.ParseInt(query.Get("block_size"), 10, 64); err == nil {
|
||||
blockSize = int(size)
|
||||
}
|
||||
if altHosts := strings.Split(query.Get("alt_hosts"), ","); len(altHosts) != 0 {
|
||||
for _, host := range altHosts {
|
||||
if len(host) != 0 {
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
}
|
||||
}
|
||||
switch query.Get("connection_open_strategy") {
|
||||
case "random":
|
||||
connOpenStrategy = connOpenRandom
|
||||
case "in_order":
|
||||
connOpenStrategy = connOpenInOrder
|
||||
case "time_random":
|
||||
connOpenStrategy = connOpenTimeRandom
|
||||
}
|
||||
|
||||
settings, err := makeQuerySettings(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if v, err := strconv.ParseBool(query.Get("compress")); err == nil {
|
||||
compress = v
|
||||
}
|
||||
|
||||
if v, err := strconv.ParseBool(query.Get("check_connection_liveness")); err == nil {
|
||||
checkConnLiveness = v
|
||||
}
|
||||
if secure {
|
||||
// There is no way to check the liveness of a secure connection, as long as there is no access to raw TCP net.Conn
|
||||
checkConnLiveness = false
|
||||
}
|
||||
|
||||
var (
|
||||
ch = clickhouse{
|
||||
logf: func(string, ...interface{}) {},
|
||||
settings: settings,
|
||||
compress: compress,
|
||||
blockSize: blockSize,
|
||||
checkConnLiveness: checkConnLiveness,
|
||||
ServerInfo: data.ServerInfo{
|
||||
Timezone: time.Local,
|
||||
},
|
||||
}
|
||||
logger = log.New(logOutput, "[clickhouse]", 0)
|
||||
)
|
||||
if debug, err := strconv.ParseBool(url.Query().Get("debug")); err == nil && debug {
|
||||
ch.logf = logger.Printf
|
||||
}
|
||||
ch.logf("host(s)=%s, database=%s, username=%s",
|
||||
strings.Join(hosts, ", "),
|
||||
database,
|
||||
username,
|
||||
)
|
||||
options := connOptions{
|
||||
secure: secure,
|
||||
tlsConfig: tlsConfig,
|
||||
skipVerify: skipVerify,
|
||||
hosts: hosts,
|
||||
connTimeout: connTimeout,
|
||||
readTimeout: readTimeout,
|
||||
writeTimeout: writeTimeout,
|
||||
noDelay: noDelay,
|
||||
openStrategy: connOpenStrategy,
|
||||
logf: ch.logf,
|
||||
}
|
||||
if ch.conn, err = dial(options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.SetPrefix(fmt.Sprintf("[clickhouse][connect=%d]", ch.conn.ident))
|
||||
ch.buffer = bufio.NewWriter(ch.conn)
|
||||
|
||||
ch.decoder = binary.NewDecoderWithCompress(ch.conn)
|
||||
ch.encoder = binary.NewEncoderWithCompress(ch.buffer)
|
||||
|
||||
if err := ch.hello(database, username, password); err != nil {
|
||||
ch.conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &ch, nil
|
||||
}
|
||||
|
||||
func (ch *clickhouse) hello(database, username, password string) error {
|
||||
ch.logf("[hello] -> %s", ch.ClientInfo)
|
||||
{
|
||||
ch.encoder.Uvarint(protocol.ClientHello)
|
||||
if err := ch.ClientInfo.Write(ch.encoder); err != nil {
|
||||
return err
|
||||
}
|
||||
{
|
||||
ch.encoder.String(database)
|
||||
ch.encoder.String(username)
|
||||
ch.encoder.String(password)
|
||||
}
|
||||
if err := ch.encoder.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
packet, err := ch.decoder.Uvarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch packet {
|
||||
case protocol.ServerException:
|
||||
return ch.exception()
|
||||
case protocol.ServerHello:
|
||||
if err := ch.ServerInfo.Read(ch.decoder); err != nil {
|
||||
return err
|
||||
}
|
||||
case protocol.ServerEndOfStream:
|
||||
ch.logf("[bootstrap] <- end of stream")
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("[hello] unexpected packet [%d] from server", packet)
|
||||
}
|
||||
}
|
||||
ch.logf("[hello] <- %s", ch.ServerInfo)
|
||||
return nil
|
||||
}
|
||||
-354
@@ -1,354 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/column"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Date = types.Date
|
||||
DateTime = types.DateTime
|
||||
UUID = types.UUID
|
||||
)
|
||||
|
||||
type ExternalTable struct {
|
||||
Name string
|
||||
Values [][]driver.Value
|
||||
Columns []column.Column
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInsertInNotBatchMode = errors.New("insert statement supported only in the batch mode (use begin/commit)")
|
||||
ErrLimitDataRequestInTx = errors.New("data request has already been prepared in transaction")
|
||||
)
|
||||
|
||||
var (
|
||||
splitInsertRe = regexp.MustCompile(`(?i)\sVALUES\s*\(`)
|
||||
)
|
||||
|
||||
type logger func(format string, v ...interface{})
|
||||
|
||||
type clickhouse struct {
|
||||
sync.Mutex
|
||||
data.ServerInfo
|
||||
data.ClientInfo
|
||||
logf logger
|
||||
conn *connect
|
||||
block *data.Block
|
||||
buffer *bufio.Writer
|
||||
decoder *binary.Decoder
|
||||
encoder *binary.Encoder
|
||||
settings *querySettings
|
||||
compress bool
|
||||
blockSize int
|
||||
inTransaction bool
|
||||
checkConnLiveness bool
|
||||
}
|
||||
|
||||
func (ch *clickhouse) Prepare(query string) (driver.Stmt, error) {
|
||||
return ch.prepareContext(context.Background(), query)
|
||||
}
|
||||
|
||||
func (ch *clickhouse) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
|
||||
return ch.prepareContext(ctx, query)
|
||||
}
|
||||
|
||||
func (ch *clickhouse) prepareContext(ctx context.Context, query string) (driver.Stmt, error) {
|
||||
ch.logf("[prepare] %s", query)
|
||||
switch {
|
||||
case ch.conn.closed:
|
||||
return nil, driver.ErrBadConn
|
||||
case ch.block != nil:
|
||||
return nil, ErrLimitDataRequestInTx
|
||||
case isInsert(query):
|
||||
if !ch.inTransaction {
|
||||
return nil, ErrInsertInNotBatchMode
|
||||
}
|
||||
return ch.insert(ctx, query)
|
||||
}
|
||||
return &stmt{
|
||||
ch: ch,
|
||||
query: query,
|
||||
numInput: numInput(query),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ch *clickhouse) insert(ctx context.Context, query string) (_ driver.Stmt, err error) {
|
||||
if err := ch.sendQuery(ctx, splitInsertRe.Split(query, -1)[0]+" VALUES ", nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ch.block, err = ch.readMeta(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &stmt{
|
||||
ch: ch,
|
||||
isInsert: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ch *clickhouse) Begin() (driver.Tx, error) {
|
||||
return ch.beginTx(context.Background(), txOptions{})
|
||||
}
|
||||
|
||||
func (ch *clickhouse) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||
return ch.beginTx(ctx, txOptions{
|
||||
Isolation: int(opts.Isolation),
|
||||
ReadOnly: opts.ReadOnly,
|
||||
})
|
||||
}
|
||||
|
||||
type txOptions struct {
|
||||
Isolation int
|
||||
ReadOnly bool
|
||||
}
|
||||
|
||||
func (ch *clickhouse) beginTx(ctx context.Context, opts txOptions) (*clickhouse, error) {
|
||||
ch.logf("[begin] tx=%t, data=%t", ch.inTransaction, ch.block != nil)
|
||||
switch {
|
||||
case ch.inTransaction:
|
||||
return nil, sql.ErrTxDone
|
||||
case ch.conn.closed:
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
|
||||
// Perform a stale connection check. We only perform this check in beginTx,
|
||||
// because database/sql retries driver.ErrBadConn only for first request,
|
||||
// but beginTx doesn't perform any other network interaction.
|
||||
if ch.checkConnLiveness {
|
||||
if err := ch.conn.connCheck(); err != nil {
|
||||
ch.logf("[begin] closing bad idle connection: %w", err)
|
||||
ch.Close()
|
||||
return ch, driver.ErrBadConn
|
||||
}
|
||||
}
|
||||
|
||||
if finish := ch.watchCancel(ctx); finish != nil {
|
||||
defer finish()
|
||||
}
|
||||
ch.block = nil
|
||||
ch.inTransaction = true
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func (ch *clickhouse) Commit() error {
|
||||
ch.logf("[commit] tx=%t, data=%t", ch.inTransaction, ch.block != nil)
|
||||
defer func() {
|
||||
if ch.block != nil {
|
||||
ch.block.Reset()
|
||||
ch.block = nil
|
||||
}
|
||||
ch.inTransaction = false
|
||||
}()
|
||||
switch {
|
||||
case !ch.inTransaction:
|
||||
return sql.ErrTxDone
|
||||
case ch.conn.closed:
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
if ch.block != nil {
|
||||
if err := ch.writeBlock(ch.block, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
// Send empty block as marker of end of data.
|
||||
if err := ch.writeBlock(&data.Block{}, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.encoder.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return ch.process()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch *clickhouse) Rollback() error {
|
||||
ch.logf("[rollback] tx=%t, data=%t", ch.inTransaction, ch.block != nil)
|
||||
if !ch.inTransaction {
|
||||
return sql.ErrTxDone
|
||||
}
|
||||
if ch.block != nil {
|
||||
ch.block.Reset()
|
||||
}
|
||||
ch.block = nil
|
||||
ch.buffer = nil
|
||||
ch.inTransaction = false
|
||||
return ch.conn.Close()
|
||||
}
|
||||
|
||||
func (ch *clickhouse) CheckNamedValue(nv *driver.NamedValue) error {
|
||||
switch nv.Value.(type) {
|
||||
case ExternalTable, column.IP, column.UUID:
|
||||
return nil
|
||||
case nil, []byte, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, string, time.Time:
|
||||
return nil
|
||||
}
|
||||
switch v := nv.Value.(type) {
|
||||
case
|
||||
[]int, []int8, []int16, []int32, []int64,
|
||||
[]uint, []uint8, []uint16, []uint32, []uint64,
|
||||
[]float32, []float64,
|
||||
[]string:
|
||||
return nil
|
||||
case net.IP, *net.IP:
|
||||
return nil
|
||||
case driver.Valuer:
|
||||
value, err := v.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nv.Value = value
|
||||
default:
|
||||
switch value := reflect.ValueOf(nv.Value); value.Kind() {
|
||||
case reflect.Slice:
|
||||
return nil
|
||||
case reflect.Bool:
|
||||
nv.Value = uint8(0)
|
||||
if value.Bool() {
|
||||
nv.Value = uint8(1)
|
||||
}
|
||||
case reflect.Int8:
|
||||
nv.Value = int8(value.Int())
|
||||
case reflect.Int16:
|
||||
nv.Value = int16(value.Int())
|
||||
case reflect.Int32:
|
||||
nv.Value = int32(value.Int())
|
||||
case reflect.Int64:
|
||||
nv.Value = value.Int()
|
||||
case reflect.Uint8:
|
||||
nv.Value = uint8(value.Uint())
|
||||
case reflect.Uint16:
|
||||
nv.Value = uint16(value.Uint())
|
||||
case reflect.Uint32:
|
||||
nv.Value = uint32(value.Uint())
|
||||
case reflect.Uint64:
|
||||
nv.Value = uint64(value.Uint())
|
||||
case reflect.Float32:
|
||||
nv.Value = float32(value.Float())
|
||||
case reflect.Float64:
|
||||
nv.Value = float64(value.Float())
|
||||
case reflect.String:
|
||||
nv.Value = value.String()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch *clickhouse) Close() error {
|
||||
ch.block = nil
|
||||
return ch.conn.Close()
|
||||
}
|
||||
|
||||
func (ch *clickhouse) process() error {
|
||||
packet, err := ch.decoder.Uvarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
switch packet {
|
||||
case protocol.ServerPong:
|
||||
ch.logf("[process] <- pong")
|
||||
return nil
|
||||
case protocol.ServerException:
|
||||
ch.logf("[process] <- exception")
|
||||
return ch.exception()
|
||||
case protocol.ServerProgress:
|
||||
progress, err := ch.progress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch.logf("[process] <- progress: rows=%d, bytes=%d, total rows=%d",
|
||||
progress.rows,
|
||||
progress.bytes,
|
||||
progress.totalRows,
|
||||
)
|
||||
case protocol.ServerProfileInfo:
|
||||
profileInfo, err := ch.profileInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch.logf("[process] <- profiling: rows=%d, bytes=%d, blocks=%d", profileInfo.rows, profileInfo.bytes, profileInfo.blocks)
|
||||
case protocol.ServerData:
|
||||
block, err := ch.readBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch.logf("[process] <- data: packet=%d, columns=%d, rows=%d", packet, block.NumColumns, block.NumRows)
|
||||
case protocol.ServerEndOfStream:
|
||||
ch.logf("[process] <- end of stream")
|
||||
return nil
|
||||
default:
|
||||
ch.conn.Close()
|
||||
return fmt.Errorf("[process] unexpected packet [%d] from server", packet)
|
||||
}
|
||||
if packet, err = ch.decoder.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *clickhouse) cancel() error {
|
||||
ch.logf("[cancel request]")
|
||||
// even if we fail to write the cancel, we still need to close
|
||||
err := ch.encoder.Uvarint(protocol.ClientCancel)
|
||||
if err == nil {
|
||||
err = ch.encoder.Flush()
|
||||
}
|
||||
// return the close error if there was one, otherwise return the write error
|
||||
if cerr := ch.conn.Close(); cerr != nil {
|
||||
return cerr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (ch *clickhouse) watchCancel(ctx context.Context) func() {
|
||||
if done := ctx.Done(); done != nil {
|
||||
finished := make(chan struct{})
|
||||
go func() {
|
||||
select {
|
||||
case <-done:
|
||||
ch.cancel()
|
||||
finished <- struct{}{}
|
||||
ch.logf("[cancel] <- done")
|
||||
case <-finished:
|
||||
ch.logf("[cancel] <- finished")
|
||||
}
|
||||
}()
|
||||
return func() {
|
||||
select {
|
||||
case <-finished:
|
||||
case finished <- struct{}{}:
|
||||
}
|
||||
}
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
|
||||
func (ch *clickhouse) ExecContext(ctx context.Context, query string,
|
||||
args []driver.NamedValue) (driver.Result, error) {
|
||||
finish := ch.watchCancel(ctx)
|
||||
defer finish()
|
||||
stmt, err := ch.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dargs := make([]driver.Value, len(args))
|
||||
for i, nv := range args {
|
||||
dargs[i] = nv.Value
|
||||
}
|
||||
return stmt.Exec(dargs)
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Exception struct {
|
||||
Code int32
|
||||
Name string
|
||||
Message string
|
||||
StackTrace string
|
||||
nested error
|
||||
}
|
||||
|
||||
func (e *Exception) Error() string {
|
||||
return fmt.Sprintf("code: %d, message: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
func (ch *clickhouse) exception() error {
|
||||
var (
|
||||
e Exception
|
||||
err error
|
||||
hasNested bool
|
||||
)
|
||||
if e.Code, err = ch.decoder.Int32(); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Name, err = ch.decoder.String(); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Message, err = ch.decoder.String(); err != nil {
|
||||
return err
|
||||
}
|
||||
e.Message = strings.TrimSpace(strings.TrimPrefix(e.Message, e.Name+":"))
|
||||
if e.StackTrace, err = ch.decoder.String(); err != nil {
|
||||
return err
|
||||
}
|
||||
if hasNested, err = ch.decoder.Bool(); err != nil {
|
||||
return err
|
||||
}
|
||||
if hasNested {
|
||||
e.nested = ch.exception()
|
||||
}
|
||||
return &e
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
)
|
||||
|
||||
func (ch *clickhouse) Ping(ctx context.Context) error {
|
||||
return ch.ping(ctx)
|
||||
}
|
||||
|
||||
func (ch *clickhouse) ping(ctx context.Context) error {
|
||||
if ch.conn.closed {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
ch.logf("-> ping")
|
||||
finish := ch.watchCancel(ctx)
|
||||
defer finish()
|
||||
if err := ch.encoder.Uvarint(protocol.ClientPing); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.encoder.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return ch.process()
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
type profileInfo struct {
|
||||
rows uint64
|
||||
bytes uint64
|
||||
blocks uint64
|
||||
appliedLimit bool
|
||||
rowsBeforeLimit uint64
|
||||
calculatedRowsBeforeLimit bool
|
||||
}
|
||||
|
||||
func (ch *clickhouse) profileInfo() (*profileInfo, error) {
|
||||
var (
|
||||
p profileInfo
|
||||
err error
|
||||
)
|
||||
if p.rows, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.blocks, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.bytes, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.appliedLimit, err = ch.decoder.Bool(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.rowsBeforeLimit, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.calculatedRowsBeforeLimit, err = ch.decoder.Bool(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
type progress struct {
|
||||
rows uint64
|
||||
bytes uint64
|
||||
totalRows uint64
|
||||
}
|
||||
|
||||
func (ch *clickhouse) progress() (*progress, error) {
|
||||
var (
|
||||
p progress
|
||||
err error
|
||||
)
|
||||
if p.rows, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.bytes, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.totalRows, err = ch.decoder.Uvarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
)
|
||||
|
||||
func (ch *clickhouse) readBlock() (*data.Block, error) {
|
||||
if _, err := ch.decoder.String(); err != nil { // temporary table
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch.decoder.SelectCompress(ch.compress)
|
||||
var block data.Block
|
||||
if err := block.Read(&ch.ServerInfo, ch.decoder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ch.decoder.SelectCompress(false)
|
||||
return &block, nil
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
)
|
||||
|
||||
func (ch *clickhouse) readMeta() (*data.Block, error) {
|
||||
for {
|
||||
packet, err := ch.decoder.Uvarint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch packet {
|
||||
case protocol.ServerException:
|
||||
ch.logf("[read meta] <- exception")
|
||||
return nil, ch.exception()
|
||||
case protocol.ServerProgress:
|
||||
progress, err := ch.progress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ch.logf("[read meta] <- progress: rows=%d, bytes=%d, total rows=%d",
|
||||
progress.rows,
|
||||
progress.bytes,
|
||||
progress.totalRows,
|
||||
)
|
||||
case protocol.ServerProfileInfo:
|
||||
profileInfo, err := ch.profileInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ch.logf("[read meta] <- profiling: rows=%d, bytes=%d, blocks=%d", profileInfo.rows, profileInfo.bytes, profileInfo.blocks)
|
||||
case protocol.ServerData:
|
||||
block, err := ch.readBlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ch.logf("[read meta] <- data: packet=%d, columns=%d, rows=%d", packet, block.NumColumns, block.NumRows)
|
||||
return block, nil
|
||||
case protocol.ServerEndOfStream:
|
||||
_, err := ch.readBlock()
|
||||
ch.logf("[process] <- end of stream")
|
||||
return nil, err
|
||||
default:
|
||||
ch.conn.Close()
|
||||
return nil, fmt.Errorf("[read meta] unexpected packet [%d] from server", packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import "github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
|
||||
func (ch *clickhouse) sendExternalTables(externalTables []ExternalTable) error {
|
||||
ch.logf("[send external tables] count %d", len(externalTables))
|
||||
if externalTables == nil || len(externalTables) == 0 {
|
||||
return nil
|
||||
}
|
||||
block := &data.Block{}
|
||||
sentTables := make(map[string]bool, 0)
|
||||
for _, externalTable := range externalTables {
|
||||
if _, ok := sentTables[externalTable.Name]; ok {
|
||||
continue
|
||||
}
|
||||
ch.logf("[send external table] name %s", externalTable.Name)
|
||||
sentTables[externalTable.Name] = true
|
||||
block.Columns = externalTable.Columns
|
||||
block.NumColumns = uint64(len(externalTable.Columns))
|
||||
for _, row := range externalTable.Values {
|
||||
err := block.AppendRow(row)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := ch.writeBlock(block, externalTable.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.encoder.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
block.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
)
|
||||
|
||||
func (ch *clickhouse) sendQuery(ctx context.Context, query string, externalTables []ExternalTable) error {
|
||||
ch.logf("[send query] %s", query)
|
||||
if err := ch.encoder.Uvarint(protocol.ClientQuery); err != nil {
|
||||
return err
|
||||
}
|
||||
var queryID string
|
||||
queryIDValue := ctx.Value(queryIDKey)
|
||||
if queryIDValue != nil {
|
||||
if queryIdStr, ok := queryIDValue.(string); ok {
|
||||
queryID = queryIdStr
|
||||
}
|
||||
}
|
||||
if err := ch.encoder.String(queryID); err != nil {
|
||||
return err
|
||||
}
|
||||
{ // client info
|
||||
ch.encoder.Uvarint(1)
|
||||
ch.encoder.String("")
|
||||
ch.encoder.String("")
|
||||
ch.encoder.String("[::ffff:127.0.0.1]:0")
|
||||
ch.encoder.Uvarint(1) // iface type TCP
|
||||
ch.encoder.String(hostname)
|
||||
ch.encoder.String(hostname)
|
||||
}
|
||||
if err := ch.ClientInfo.Write(ch.encoder); err != nil {
|
||||
return err
|
||||
}
|
||||
if ch.ServerInfo.Revision >= protocol.DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO {
|
||||
ch.encoder.String("")
|
||||
}
|
||||
|
||||
// the settings are written as list of contiguous name-value pairs, finished with empty name
|
||||
if !ch.settings.IsEmpty() {
|
||||
ch.logf("[query settings] %s", ch.settings.settingsStr)
|
||||
if err := ch.settings.Serialize(ch.encoder); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// empty string is a marker of the end of the settings
|
||||
if err := ch.encoder.String(""); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.encoder.Uvarint(protocol.StateComplete); err != nil {
|
||||
return err
|
||||
}
|
||||
compress := protocol.CompressDisable
|
||||
if ch.compress {
|
||||
compress = protocol.CompressEnable
|
||||
}
|
||||
if err := ch.encoder.Uvarint(compress); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.encoder.String(query); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.sendExternalTables(externalTables); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ch.writeBlock(&data.Block{}, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return ch.encoder.Flush()
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/data"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
)
|
||||
|
||||
func (ch *clickhouse) writeBlock(block *data.Block, tableName string) error {
|
||||
ch.Lock()
|
||||
defer ch.Unlock()
|
||||
if err := ch.encoder.Uvarint(protocol.ClientData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ch.encoder.String(tableName); err != nil { // temporary table
|
||||
return err
|
||||
}
|
||||
|
||||
// implement CityHash v 1.0.2 and add LZ4 compression
|
||||
/*
|
||||
From Alexey Milovidov
|
||||
Насколько я помню, сжимаются блоки с данными Native формата, а всё остальное (всякие номера пакетов и т. п.) передаётся без сжатия.
|
||||
|
||||
Сжатые данные устроены так. Они представляют собой набор сжатых фреймов.
|
||||
Каждый фрейм имеет следующий вид:
|
||||
чексумма (16 байт),
|
||||
идентификатор алгоритма сжатия (1 байт),
|
||||
размер сжатых данных (4 байта, little endian, размер не включает в себя чексумму, но включает в себя остальные 9 байт заголовка),
|
||||
размер несжатых данных (4 байта, little endian), затем сжатые данные.
|
||||
Идентификатор алгоритма: 0x82 - lz4, 0x90 - zstd.
|
||||
Чексумма - CityHash128 из CityHash версии 1.0.2, вычисленный от сжатых данных с учётом 9 байт заголовка.
|
||||
|
||||
См. CompressedReadBufferBase, CompressedWriteBuffer,
|
||||
utils/compressor, TCPHandler.
|
||||
*/
|
||||
ch.encoder.SelectCompress(ch.compress)
|
||||
err := block.Write(&ch.ServerInfo, ch.encoder)
|
||||
ch.encoder.SelectCompress(false)
|
||||
return err
|
||||
}
|
||||
-225
@@ -1,225 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"database/sql/driver"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var tick int32
|
||||
|
||||
type openStrategy int8
|
||||
|
||||
func (s openStrategy) String() string {
|
||||
switch s {
|
||||
case connOpenInOrder:
|
||||
return "in_order"
|
||||
case connOpenTimeRandom:
|
||||
return "time_random"
|
||||
}
|
||||
return "random"
|
||||
}
|
||||
|
||||
const (
|
||||
connOpenRandom openStrategy = iota + 1
|
||||
connOpenInOrder
|
||||
connOpenTimeRandom
|
||||
)
|
||||
|
||||
type connOptions struct {
|
||||
secure, skipVerify bool
|
||||
tlsConfig *tls.Config
|
||||
hosts []string
|
||||
connTimeout, readTimeout, writeTimeout time.Duration
|
||||
noDelay bool
|
||||
openStrategy openStrategy
|
||||
logf func(string, ...interface{})
|
||||
}
|
||||
|
||||
// DialFunc is a function which can be used to establish the network connection.
|
||||
// Custom dial functions must be registered with RegisterDial
|
||||
type DialFunc func(network, address string, timeout time.Duration, config *tls.Config) (net.Conn, error)
|
||||
|
||||
var (
|
||||
customDialLock sync.RWMutex
|
||||
customDial DialFunc
|
||||
)
|
||||
|
||||
// RegisterDial registers a custom dial function.
|
||||
func RegisterDial(dial DialFunc) {
|
||||
customDialLock.Lock()
|
||||
customDial = dial
|
||||
customDialLock.Unlock()
|
||||
}
|
||||
|
||||
// DeregisterDial deregisters the custom dial function.
|
||||
func DeregisterDial() {
|
||||
customDialLock.Lock()
|
||||
customDial = nil
|
||||
customDialLock.Unlock()
|
||||
}
|
||||
func dial(options connOptions) (*connect, error) {
|
||||
var (
|
||||
err error
|
||||
abs = func(v int) int {
|
||||
if v < 0 {
|
||||
return -1 * v
|
||||
}
|
||||
return v
|
||||
}
|
||||
conn net.Conn
|
||||
ident = abs(int(atomic.AddInt32(&tick, 1)))
|
||||
)
|
||||
tlsConfig := options.tlsConfig
|
||||
if options.secure {
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = &tls.Config{}
|
||||
}
|
||||
tlsConfig.InsecureSkipVerify = options.skipVerify
|
||||
}
|
||||
checkedHosts := make(map[int]struct{}, len(options.hosts))
|
||||
for i := range options.hosts {
|
||||
var num int
|
||||
switch options.openStrategy {
|
||||
case connOpenInOrder:
|
||||
num = i
|
||||
case connOpenRandom:
|
||||
num = (ident + i) % len(options.hosts)
|
||||
case connOpenTimeRandom:
|
||||
// select host based on milliseconds
|
||||
num = int((time.Now().UnixNano()/1000)%1000) % len(options.hosts)
|
||||
for _, ok := checkedHosts[num]; ok; _, ok = checkedHosts[num] {
|
||||
num = int(time.Now().UnixNano()) % len(options.hosts)
|
||||
}
|
||||
checkedHosts[num] = struct{}{}
|
||||
}
|
||||
customDialLock.RLock()
|
||||
cd := customDial
|
||||
customDialLock.RUnlock()
|
||||
switch {
|
||||
case options.secure:
|
||||
if cd != nil {
|
||||
conn, err = cd("tcp", options.hosts[num], options.connTimeout, tlsConfig)
|
||||
} else {
|
||||
conn, err = tls.DialWithDialer(
|
||||
&net.Dialer{
|
||||
Timeout: options.connTimeout,
|
||||
},
|
||||
"tcp",
|
||||
options.hosts[num],
|
||||
tlsConfig,
|
||||
)
|
||||
}
|
||||
default:
|
||||
if cd != nil {
|
||||
conn, err = cd("tcp", options.hosts[num], options.connTimeout, nil)
|
||||
} else {
|
||||
conn, err = net.DialTimeout("tcp", options.hosts[num], options.connTimeout)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
options.logf(
|
||||
"[dial] secure=%t, skip_verify=%t, strategy=%s, ident=%d, server=%d -> %s",
|
||||
options.secure,
|
||||
options.skipVerify,
|
||||
options.openStrategy,
|
||||
ident,
|
||||
num,
|
||||
conn.RemoteAddr(),
|
||||
)
|
||||
if tcp, ok := conn.(*net.TCPConn); ok {
|
||||
err = tcp.SetNoDelay(options.noDelay) // Disable or enable the Nagle Algorithm for this tcp socket
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &connect{
|
||||
Conn: conn,
|
||||
logf: options.logf,
|
||||
ident: ident,
|
||||
buffer: bufio.NewReader(conn),
|
||||
readTimeout: options.readTimeout,
|
||||
writeTimeout: options.writeTimeout,
|
||||
}, nil
|
||||
} else {
|
||||
options.logf(
|
||||
"[dial err] secure=%t, skip_verify=%t, strategy=%s, ident=%d, addr=%s\n%#v",
|
||||
options.secure,
|
||||
options.skipVerify,
|
||||
options.openStrategy,
|
||||
ident,
|
||||
options.hosts[num],
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type connect struct {
|
||||
net.Conn
|
||||
logf func(string, ...interface{})
|
||||
ident int
|
||||
buffer *bufio.Reader
|
||||
closed bool
|
||||
readTimeout time.Duration
|
||||
writeTimeout time.Duration
|
||||
lastReadDeadlineTime time.Time
|
||||
lastWriteDeadlineTime time.Time
|
||||
}
|
||||
|
||||
func (conn *connect) Read(b []byte) (int, error) {
|
||||
var (
|
||||
n int
|
||||
err error
|
||||
total int
|
||||
dstLen = len(b)
|
||||
)
|
||||
if currentTime := now(); conn.readTimeout != 0 && currentTime.Sub(conn.lastReadDeadlineTime) > (conn.readTimeout>>2) {
|
||||
conn.SetReadDeadline(time.Now().Add(conn.readTimeout))
|
||||
conn.lastReadDeadlineTime = currentTime
|
||||
}
|
||||
for total < dstLen {
|
||||
if n, err = conn.buffer.Read(b[total:]); err != nil {
|
||||
conn.logf("[connect] read error: %v", err)
|
||||
conn.Close()
|
||||
return n, driver.ErrBadConn
|
||||
}
|
||||
total += n
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (conn *connect) Write(b []byte) (int, error) {
|
||||
var (
|
||||
n int
|
||||
err error
|
||||
total int
|
||||
srcLen = len(b)
|
||||
)
|
||||
if currentTime := now(); conn.writeTimeout != 0 && currentTime.Sub(conn.lastWriteDeadlineTime) > (conn.writeTimeout>>2) {
|
||||
conn.SetWriteDeadline(time.Now().Add(conn.writeTimeout))
|
||||
conn.lastWriteDeadlineTime = currentTime
|
||||
}
|
||||
for total < srcLen {
|
||||
if n, err = conn.Conn.Write(b[total:]); err != nil {
|
||||
conn.logf("[connect] write error: %v", err)
|
||||
conn.Close()
|
||||
return n, driver.ErrBadConn
|
||||
}
|
||||
total += n
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (conn *connect) Close() error {
|
||||
if !conn.closed {
|
||||
conn.closed = true
|
||||
return conn.Conn.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos
|
||||
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errUnexpectedRead = errors.New("unexpected read from socket")
|
||||
|
||||
func (conn *connect) connCheck() error {
|
||||
var sysErr error
|
||||
|
||||
sysConn, ok := conn.Conn.(syscall.Conn)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
rawConn, err := sysConn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If this connection has a ReadTimeout which we've been setting on
|
||||
// reads, reset it to zero value before we attempt a non-blocking
|
||||
// read, otherwise we may get os.ErrDeadlineExceeded for the cached
|
||||
// connection from the pool with an expired timeout.
|
||||
if conn.readTimeout != 0 {
|
||||
err = conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("set read deadline: %w", err)
|
||||
}
|
||||
conn.lastReadDeadlineTime = time.Time{}
|
||||
}
|
||||
err = rawConn.Read(func(fd uintptr) bool {
|
||||
var buf [1]byte
|
||||
n, err := syscall.Read(int(fd), buf[:])
|
||||
switch {
|
||||
case n == 0 && err == nil:
|
||||
sysErr = io.EOF
|
||||
case n > 0:
|
||||
sysErr = errUnexpectedRead
|
||||
case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK:
|
||||
sysErr = nil
|
||||
default:
|
||||
sysErr = err
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sysErr
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos
|
||||
|
||||
package clickhouse
|
||||
|
||||
func (conn *connect) connCheck() error {
|
||||
return nil
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
---
|
||||
version: '3'
|
||||
services:
|
||||
clickhouse:
|
||||
image: yandex/clickhouse-server
|
||||
ports:
|
||||
- 127.0.0.1:8123:8123
|
||||
- 127.0.0.1:9000:9000
|
||||
- 127.0.0.1:9009:9009
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
module github.com/ClickHouse/clickhouse-go
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/bkaradzic/go-lz4 v1.0.0
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible
|
||||
github.com/stretchr/testify v1.3.0
|
||||
)
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func numInput(query string) int {
|
||||
|
||||
var (
|
||||
count int
|
||||
args = make(map[string]struct{})
|
||||
reader = bytes.NewReader([]byte(query))
|
||||
quote, gravis bool
|
||||
escape bool
|
||||
keyword bool
|
||||
inBetween bool
|
||||
like = newMatcher("like")
|
||||
limit = newMatcher("limit")
|
||||
offset = newMatcher("offset")
|
||||
between = newMatcher("between")
|
||||
in = newMatcher("in")
|
||||
and = newMatcher("and")
|
||||
from = newMatcher("from")
|
||||
join = newMatcher("join")
|
||||
subSelect = newMatcher("select")
|
||||
)
|
||||
for {
|
||||
if char, _, err := reader.ReadRune(); err == nil {
|
||||
if escape {
|
||||
escape = false
|
||||
continue
|
||||
}
|
||||
switch char {
|
||||
case '\\':
|
||||
if gravis || quote {
|
||||
escape = true
|
||||
}
|
||||
case '\'':
|
||||
if !gravis {
|
||||
quote = !quote
|
||||
}
|
||||
case '`':
|
||||
if !quote {
|
||||
gravis = !gravis
|
||||
}
|
||||
}
|
||||
if quote || gravis {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case char == '?' && keyword:
|
||||
count++
|
||||
case char == '@':
|
||||
if param := paramParser(reader); len(param) != 0 {
|
||||
if _, found := args[param]; !found {
|
||||
args[param] = struct{}{}
|
||||
count++
|
||||
}
|
||||
}
|
||||
case
|
||||
char == '=',
|
||||
char == '<',
|
||||
char == '>',
|
||||
char == '(',
|
||||
char == ',',
|
||||
char == '[',
|
||||
char == '%':
|
||||
keyword = true
|
||||
default:
|
||||
if limit.matchRune(char) || offset.matchRune(char) || like.matchRune(char) ||
|
||||
in.matchRune(char) || from.matchRune(char) || join.matchRune(char) || subSelect.matchRune(char) {
|
||||
keyword = true
|
||||
} else if between.matchRune(char) {
|
||||
keyword = true
|
||||
inBetween = true
|
||||
} else if inBetween && and.matchRune(char) {
|
||||
keyword = true
|
||||
inBetween = false
|
||||
} else {
|
||||
keyword = keyword && (char == ' ' || char == '\t' || char == '\n')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func paramParser(reader *bytes.Reader) string {
|
||||
var name bytes.Buffer
|
||||
for {
|
||||
if char, _, err := reader.ReadRune(); err == nil {
|
||||
if char == '_' || char >= '0' && char <= '9' || 'a' <= char && char <= 'z' || 'A' <= char && char <= 'Z' {
|
||||
name.WriteRune(char)
|
||||
} else {
|
||||
reader.UnreadRune()
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return name.String()
|
||||
}
|
||||
|
||||
var selectRe = regexp.MustCompile(`\s+SELECT\s+`)
|
||||
|
||||
func isInsert(query string) bool {
|
||||
if f := strings.Fields(query); len(f) > 2 {
|
||||
return strings.EqualFold("INSERT", f[0]) && strings.EqualFold("INTO", f[1]) && !selectRe.MatchString(strings.ToUpper(query))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func quote(v driver.Value) string {
|
||||
switch v := reflect.ValueOf(v); v.Kind() {
|
||||
case reflect.Slice:
|
||||
values := make([]string, 0, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
values = append(values, quote(v.Index(i).Interface()))
|
||||
}
|
||||
return strings.Join(values, ", ")
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return "'" + strings.NewReplacer(`\`, `\\`, `'`, `\'`).Replace(v) + "'"
|
||||
case time.Time:
|
||||
return formatTime(v)
|
||||
case nil:
|
||||
return "null"
|
||||
}
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
|
||||
func formatTime(v time.Time) string {
|
||||
return v.Format("toDateTime('2006-01-02 15:04:05', '" + v.Location().String() + "')")
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
// +build !clz4
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/lz4"
|
||||
)
|
||||
|
||||
type compressReader struct {
|
||||
reader io.Reader
|
||||
// data uncompressed
|
||||
data []byte
|
||||
// data position
|
||||
pos int
|
||||
// data compressed
|
||||
zdata []byte
|
||||
// lz4 headers
|
||||
header []byte
|
||||
}
|
||||
|
||||
// NewCompressReader wrap the io.Reader
|
||||
func NewCompressReader(r io.Reader) *compressReader {
|
||||
p := &compressReader{
|
||||
reader: r,
|
||||
header: make([]byte, HeaderSize),
|
||||
}
|
||||
p.data = make([]byte, BlockMaxSize, BlockMaxSize)
|
||||
|
||||
zlen := lz4.CompressBound(BlockMaxSize) + HeaderSize
|
||||
p.zdata = make([]byte, zlen, zlen)
|
||||
|
||||
p.pos = len(p.data)
|
||||
return p
|
||||
}
|
||||
|
||||
func (cr *compressReader) Read(buf []byte) (n int, err error) {
|
||||
var bytesRead = 0
|
||||
n = len(buf)
|
||||
|
||||
if cr.pos < len(cr.data) {
|
||||
copyedSize := copy(buf, cr.data[cr.pos:])
|
||||
|
||||
bytesRead += copyedSize
|
||||
cr.pos += copyedSize
|
||||
}
|
||||
|
||||
for bytesRead < n {
|
||||
if err = cr.readCompressedData(); err != nil {
|
||||
return bytesRead, err
|
||||
}
|
||||
copyedSize := copy(buf[bytesRead:], cr.data)
|
||||
|
||||
bytesRead += copyedSize
|
||||
cr.pos = copyedSize
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (cr *compressReader) readCompressedData() (err error) {
|
||||
cr.pos = 0
|
||||
var n int
|
||||
n, err = cr.reader.Read(cr.header)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != len(cr.header) {
|
||||
return fmt.Errorf("Lz4 decompression header EOF")
|
||||
}
|
||||
|
||||
compressedSize := int(binary.LittleEndian.Uint32(cr.header[17:])) - 9
|
||||
decompressedSize := int(binary.LittleEndian.Uint32(cr.header[21:]))
|
||||
|
||||
if compressedSize > cap(cr.zdata) {
|
||||
cr.zdata = make([]byte, compressedSize)
|
||||
}
|
||||
if decompressedSize > cap(cr.data) {
|
||||
cr.data = make([]byte, decompressedSize)
|
||||
}
|
||||
|
||||
cr.zdata = cr.zdata[:compressedSize]
|
||||
cr.data = cr.data[:decompressedSize]
|
||||
|
||||
// @TODO checksum
|
||||
if cr.header[16] == LZ4 {
|
||||
n, err = cr.reader.Read(cr.zdata)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n != len(cr.zdata) {
|
||||
return fmt.Errorf("Decompress read size not match")
|
||||
}
|
||||
|
||||
_, err = lz4.Decode(cr.data, cr.zdata)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("Unknown compression method: 0x%02x ", cr.header[16])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
// +build clz4
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
lz4 "github.com/cloudflare/golz4"
|
||||
)
|
||||
|
||||
type compressReader struct {
|
||||
reader io.Reader
|
||||
// data uncompressed
|
||||
data []byte
|
||||
// data position
|
||||
pos int
|
||||
// data compressed
|
||||
zdata []byte
|
||||
// lz4 headers
|
||||
header []byte
|
||||
}
|
||||
|
||||
// NewCompressReader wrap the io.Reader
|
||||
func NewCompressReader(r io.Reader) *compressReader {
|
||||
p := &compressReader{
|
||||
reader: r,
|
||||
header: make([]byte, HeaderSize),
|
||||
}
|
||||
p.data = make([]byte, BlockMaxSize, BlockMaxSize)
|
||||
|
||||
zlen := lz4.CompressBound(p.data) + HeaderSize
|
||||
p.zdata = make([]byte, zlen, zlen)
|
||||
|
||||
p.pos = len(p.data)
|
||||
return p
|
||||
}
|
||||
|
||||
func (cr *compressReader) Read(buf []byte) (n int, err error) {
|
||||
var bytesRead = 0
|
||||
n = len(buf)
|
||||
|
||||
if cr.pos < len(cr.data) {
|
||||
copyedSize := copy(buf, cr.data[cr.pos:])
|
||||
|
||||
bytesRead += copyedSize
|
||||
cr.pos += copyedSize
|
||||
}
|
||||
|
||||
for bytesRead < n {
|
||||
if err = cr.readCompressedData(); err != nil {
|
||||
return bytesRead, err
|
||||
}
|
||||
copyedSize := copy(buf[bytesRead:], cr.data)
|
||||
|
||||
bytesRead += copyedSize
|
||||
cr.pos = copyedSize
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (cr *compressReader) readCompressedData() (err error) {
|
||||
cr.pos = 0
|
||||
var n int
|
||||
n, err = cr.reader.Read(cr.header)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != len(cr.header) {
|
||||
return fmt.Errorf("Lz4 decompression header EOF")
|
||||
}
|
||||
|
||||
compressedSize := int(binary.LittleEndian.Uint32(cr.header[17:])) - 9
|
||||
decompressedSize := int(binary.LittleEndian.Uint32(cr.header[21:]))
|
||||
|
||||
if compressedSize > cap(cr.zdata) {
|
||||
cr.zdata = make([]byte, compressedSize)
|
||||
}
|
||||
if decompressedSize > cap(cr.data) {
|
||||
cr.data = make([]byte, decompressedSize)
|
||||
}
|
||||
|
||||
cr.zdata = cr.zdata[:compressedSize]
|
||||
cr.data = cr.data[:decompressedSize]
|
||||
|
||||
// @TODO checksum
|
||||
if cr.header[16] == LZ4 {
|
||||
n, err = cr.reader.Read(cr.zdata)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n != len(cr.zdata) {
|
||||
return fmt.Errorf("Decompress read size not match")
|
||||
}
|
||||
|
||||
err = lz4.Uncompress(cr.zdata, cr.data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("Unknown compression method: 0x%02x ", cr.header[16])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package binary
|
||||
|
||||
type CompressionMethodByte byte
|
||||
|
||||
const (
|
||||
NONE CompressionMethodByte = 0x02
|
||||
LZ4 = 0x82
|
||||
ZSTD = 0x90
|
||||
)
|
||||
|
||||
const (
|
||||
// ChecksumSize is 128bits for cityhash102 checksum
|
||||
ChecksumSize = 16
|
||||
// CompressHeader magic + compressed_size + uncompressed_size
|
||||
CompressHeaderSize = 1 + 4 + 4
|
||||
|
||||
// HeaderSize
|
||||
HeaderSize = ChecksumSize + CompressHeaderSize
|
||||
// BlockMaxSize 1MB
|
||||
BlockMaxSize = 1 << 20
|
||||
)
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
// +build !clz4
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/cityhash102"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/lz4"
|
||||
)
|
||||
|
||||
type compressWriter struct {
|
||||
writer io.Writer
|
||||
// data uncompressed
|
||||
data []byte
|
||||
// data position
|
||||
pos int
|
||||
// data compressed
|
||||
zdata []byte
|
||||
}
|
||||
|
||||
// NewCompressWriter wrap the io.Writer
|
||||
func NewCompressWriter(w io.Writer) *compressWriter {
|
||||
p := &compressWriter{writer: w}
|
||||
p.data = make([]byte, BlockMaxSize, BlockMaxSize)
|
||||
|
||||
zlen := lz4.CompressBound(BlockMaxSize) + HeaderSize
|
||||
p.zdata = make([]byte, zlen, zlen)
|
||||
return p
|
||||
}
|
||||
|
||||
func (cw *compressWriter) Write(buf []byte) (int, error) {
|
||||
var n int
|
||||
for len(buf) > 0 {
|
||||
// Accumulate the data to be compressed.
|
||||
m := copy(cw.data[cw.pos:], buf)
|
||||
cw.pos += m
|
||||
buf = buf[m:]
|
||||
|
||||
if cw.pos == len(cw.data) {
|
||||
err := cw.Flush()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
n += m
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (cw *compressWriter) Flush() (err error) {
|
||||
if cw.pos == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// write the headers
|
||||
compressedSize, err := lz4.Encode(cw.zdata[HeaderSize:], cw.data[:cw.pos])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
compressedSize += CompressHeaderSize
|
||||
// fill the header, compressed_size_32 + uncompressed_size_32
|
||||
cw.zdata[16] = LZ4
|
||||
binary.LittleEndian.PutUint32(cw.zdata[17:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint32(cw.zdata[21:], uint32(cw.pos))
|
||||
|
||||
// fill the checksum
|
||||
checkSum := cityhash102.CityHash128(cw.zdata[16:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint64(cw.zdata[0:], checkSum.Lower64())
|
||||
binary.LittleEndian.PutUint64(cw.zdata[8:], checkSum.Higher64())
|
||||
|
||||
cw.writer.Write(cw.zdata[:compressedSize+ChecksumSize])
|
||||
if w, ok := cw.writer.(WriteFlusher); ok {
|
||||
err = w.Flush()
|
||||
}
|
||||
cw.pos = 0
|
||||
return
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
// +build clz4
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
lz4 "github.com/cloudflare/golz4"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/cityhash102"
|
||||
)
|
||||
|
||||
type compressWriter struct {
|
||||
writer io.Writer
|
||||
// data uncompressed
|
||||
data []byte
|
||||
// data position
|
||||
pos int
|
||||
// data compressed
|
||||
zdata []byte
|
||||
}
|
||||
|
||||
// NewCompressWriter wrap the io.Writer
|
||||
func NewCompressWriter(w io.Writer) *compressWriter {
|
||||
p := &compressWriter{writer: w}
|
||||
p.data = make([]byte, BlockMaxSize, BlockMaxSize)
|
||||
|
||||
zlen := lz4.CompressBound(p.data) + HeaderSize
|
||||
p.zdata = make([]byte, zlen, zlen)
|
||||
return p
|
||||
}
|
||||
|
||||
func (cw *compressWriter) Write(buf []byte) (int, error) {
|
||||
var n int
|
||||
for len(buf) > 0 {
|
||||
// Accumulate the data to be compressed.
|
||||
m := copy(cw.data[cw.pos:], buf)
|
||||
cw.pos += m
|
||||
buf = buf[m:]
|
||||
|
||||
if cw.pos == len(cw.data) {
|
||||
err := cw.Flush()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
n += m
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (cw *compressWriter) Flush() (err error) {
|
||||
if cw.pos == 0 {
|
||||
return
|
||||
}
|
||||
// write the headers
|
||||
compressedSize, err := lz4.Compress(cw.data[:cw.pos], cw.zdata[HeaderSize:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
compressedSize += CompressHeaderSize
|
||||
// fill the header, compressed_size_32 + uncompressed_size_32
|
||||
cw.zdata[16] = LZ4
|
||||
binary.LittleEndian.PutUint32(cw.zdata[17:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint32(cw.zdata[21:], uint32(cw.pos))
|
||||
|
||||
// fill the checksum
|
||||
checkSum := cityhash102.CityHash128(cw.zdata[16:], uint32(compressedSize))
|
||||
binary.LittleEndian.PutUint64(cw.zdata[0:], checkSum.Lower64())
|
||||
binary.LittleEndian.PutUint64(cw.zdata[8:], checkSum.Higher64())
|
||||
|
||||
cw.writer.Write(cw.zdata[:compressedSize+ChecksumSize])
|
||||
if w, ok := cw.writer.(WriteFlusher); ok {
|
||||
err = w.Flush()
|
||||
}
|
||||
cw.pos = 0
|
||||
return
|
||||
}
|
||||
-199
@@ -1,199 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
output: w,
|
||||
}
|
||||
}
|
||||
|
||||
func NewEncoderWithCompress(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
output: w,
|
||||
compressOutput: NewCompressWriter(w),
|
||||
}
|
||||
}
|
||||
|
||||
type Encoder struct {
|
||||
compress bool
|
||||
output io.Writer
|
||||
compressOutput io.Writer
|
||||
scratch [binary.MaxVarintLen64]byte
|
||||
}
|
||||
|
||||
func (enc *Encoder) SelectCompress(compress bool) {
|
||||
if enc.compressOutput == nil {
|
||||
return
|
||||
}
|
||||
if enc.compress && !compress {
|
||||
enc.Flush()
|
||||
}
|
||||
enc.compress = compress
|
||||
}
|
||||
|
||||
func (enc *Encoder) Get() io.Writer {
|
||||
if enc.compress && enc.compressOutput != nil {
|
||||
return enc.compressOutput
|
||||
}
|
||||
return enc.output
|
||||
}
|
||||
|
||||
func (enc *Encoder) Uvarint(v uint64) error {
|
||||
ln := binary.PutUvarint(enc.scratch[:binary.MaxVarintLen64], v)
|
||||
if _, err := enc.Get().Write(enc.scratch[0:ln]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) Bool(v bool) error {
|
||||
if v {
|
||||
return enc.UInt8(1)
|
||||
}
|
||||
return enc.UInt8(0)
|
||||
}
|
||||
|
||||
func (enc *Encoder) Int8(v int8) error {
|
||||
return enc.UInt8(uint8(v))
|
||||
}
|
||||
|
||||
func (enc *Encoder) Int16(v int16) error {
|
||||
return enc.UInt16(uint16(v))
|
||||
}
|
||||
|
||||
func (enc *Encoder) Int32(v int32) error {
|
||||
return enc.UInt32(uint32(v))
|
||||
}
|
||||
|
||||
func (enc *Encoder) Int64(v int64) error {
|
||||
return enc.UInt64(uint64(v))
|
||||
}
|
||||
|
||||
func (enc *Encoder) UInt8(v uint8) error {
|
||||
enc.scratch[0] = v
|
||||
if _, err := enc.Get().Write(enc.scratch[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) UInt16(v uint16) error {
|
||||
enc.scratch[0] = byte(v)
|
||||
enc.scratch[1] = byte(v >> 8)
|
||||
if _, err := enc.Get().Write(enc.scratch[:2]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) UInt32(v uint32) error {
|
||||
enc.scratch[0] = byte(v)
|
||||
enc.scratch[1] = byte(v >> 8)
|
||||
enc.scratch[2] = byte(v >> 16)
|
||||
enc.scratch[3] = byte(v >> 24)
|
||||
if _, err := enc.Get().Write(enc.scratch[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) UInt64(v uint64) error {
|
||||
enc.scratch[0] = byte(v)
|
||||
enc.scratch[1] = byte(v >> 8)
|
||||
enc.scratch[2] = byte(v >> 16)
|
||||
enc.scratch[3] = byte(v >> 24)
|
||||
enc.scratch[4] = byte(v >> 32)
|
||||
enc.scratch[5] = byte(v >> 40)
|
||||
enc.scratch[6] = byte(v >> 48)
|
||||
enc.scratch[7] = byte(v >> 56)
|
||||
if _, err := enc.Get().Write(enc.scratch[:8]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) Float32(v float32) error {
|
||||
return enc.UInt32(math.Float32bits(v))
|
||||
}
|
||||
|
||||
func (enc *Encoder) Float64(v float64) error {
|
||||
return enc.UInt64(math.Float64bits(v))
|
||||
}
|
||||
|
||||
func (enc *Encoder) String(v string) error {
|
||||
str := Str2Bytes(v)
|
||||
if err := enc.Uvarint(uint64(len(str))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := enc.Get().Write(str); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) RawString(str []byte) error {
|
||||
if err := enc.Uvarint(uint64(len(str))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := enc.Get().Write(str); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) Decimal128(bytes []byte) error {
|
||||
_, err := enc.Get().Write(bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
func (enc *Encoder) Write(b []byte) (int, error) {
|
||||
return enc.Get().Write(b)
|
||||
}
|
||||
|
||||
func (enc *Encoder) Flush() error {
|
||||
if w, ok := enc.Get().(WriteFlusher); ok {
|
||||
return w.Flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WriteFlusher interface {
|
||||
Flush() error
|
||||
}
|
||||
|
||||
func Str2Bytes(str string) []byte {
|
||||
// Copied from https://github.com/m3db/m3/blob/master/src/x/unsafe/string.go#L62
|
||||
if len(str) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We need to declare a real byte slice so internally the compiler
|
||||
// knows to use an unsafe.Pointer to keep track of the underlying memory so that
|
||||
// once the slice's array pointer is updated with the pointer to the string's
|
||||
// underlying bytes, the compiler won't prematurely GC the memory when the string
|
||||
// goes out of scope.
|
||||
var b []byte
|
||||
byteHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
|
||||
// This makes sure that even if GC relocates the string's underlying
|
||||
// memory after this assignment, the corresponding unsafe.Pointer in the internal
|
||||
// slice struct will be updated accordingly to reflect the memory relocation.
|
||||
byteHeader.Data = (*reflect.StringHeader)(unsafe.Pointer(&str)).Data
|
||||
|
||||
// It is important that we access str after we assign the Data
|
||||
// pointer of the string header to the Data pointer of the slice header to
|
||||
// make sure the string (and the underlying bytes backing the string) don't get
|
||||
// GC'ed before the assignment happens.
|
||||
l := len(str)
|
||||
byteHeader.Len = l
|
||||
byteHeader.Cap = l
|
||||
|
||||
return b
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
package cityhash102
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type City64 struct {
|
||||
s []byte
|
||||
}
|
||||
|
||||
var _ hash.Hash64 = (*City64)(nil)
|
||||
var _ hash.Hash = (*City64)(nil)
|
||||
|
||||
func New64() hash.Hash64 {
|
||||
return &City64{}
|
||||
}
|
||||
|
||||
func (this *City64) Sum(b []byte) []byte {
|
||||
b2 := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b2, this.Sum64())
|
||||
b = append(b, b2...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (this *City64) Sum64() uint64 {
|
||||
return CityHash64(this.s, uint32(len(this.s)))
|
||||
}
|
||||
|
||||
func (this *City64) Reset() {
|
||||
this.s = this.s[0:0]
|
||||
}
|
||||
|
||||
func (this *City64) BlockSize() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (this *City64) Write(s []byte) (n int, err error) {
|
||||
this.s = append(this.s, s...)
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
func (this *City64) Size() int {
|
||||
return 8
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
/** COPY from https://github.com/zentures/cityhash/
|
||||
|
||||
NOTE: The code is modified to be compatible with CityHash128 used in ClickHouse
|
||||
*/
|
||||
package cityhash102
|
||||
-270
@@ -1,270 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type columnDecoder func() (interface{}, error)
|
||||
|
||||
var unsupportedArrayTypeErrTemp = "unsupported Array type '%s'"
|
||||
|
||||
// If you add Nullable type, that can be used in Array(Nullable(T)) add this type to ../codegen/nullable_appender/main.go in structure values.Types.
|
||||
// Run code generation.
|
||||
//go:generate go run ../codegen/nullable_appender -package $GOPACKAGE -file nullable_appender.go
|
||||
type Array struct {
|
||||
base
|
||||
depth int
|
||||
column Column
|
||||
nullable bool
|
||||
}
|
||||
|
||||
func (array *Array) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
return nil, fmt.Errorf("do not use Read method for Array(T) column")
|
||||
}
|
||||
|
||||
func (array *Array) WriteNull(nulls, encoder *binary.Encoder, v interface{}) error {
|
||||
if array.nullable {
|
||||
column, ok := array.column.(*Nullable)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot convert to nullable type")
|
||||
}
|
||||
return column.WriteNull(nulls, encoder, v)
|
||||
}
|
||||
return fmt.Errorf("write null to not nullable array")
|
||||
}
|
||||
|
||||
func (array *Array) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
return array.column.Write(encoder, v)
|
||||
}
|
||||
|
||||
func (array *Array) ReadArray(decoder *binary.Decoder, rows int) (_ []interface{}, err error) {
|
||||
var (
|
||||
offsets = make([][]uint64, array.depth)
|
||||
values = make([]interface{}, rows)
|
||||
)
|
||||
|
||||
// Read offsets
|
||||
lastOffset := uint64(rows)
|
||||
for i := 0; i < array.depth; i++ {
|
||||
offset := make([]uint64, lastOffset)
|
||||
for j := uint64(0); j < lastOffset; j++ {
|
||||
if offset[j], err = decoder.UInt64(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
offsets[i] = offset
|
||||
lastOffset = 0
|
||||
if len(offset) > 0 {
|
||||
lastOffset = offset[len(offset)-1]
|
||||
}
|
||||
}
|
||||
|
||||
var cd columnDecoder
|
||||
|
||||
switch column := array.column.(type) {
|
||||
case *Nullable:
|
||||
nullRows, err := column.ReadNull(decoder, int(lastOffset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cd = func(rows []interface{}) columnDecoder {
|
||||
i := 0
|
||||
return func() (interface{}, error) {
|
||||
if i > len(rows) {
|
||||
return nil, errors.New("not enough rows to return while parsing Null column")
|
||||
}
|
||||
ret := rows[i]
|
||||
i++
|
||||
return ret, nil
|
||||
}
|
||||
}(nullRows)
|
||||
case *Tuple:
|
||||
tupleRows, err := column.ReadTuple(decoder, int(lastOffset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// closure to return fully assembled tuple values as if they
|
||||
// were decoded one at a time
|
||||
cd = func(rows []interface{}) columnDecoder {
|
||||
i := 0
|
||||
return func() (interface{}, error) {
|
||||
if i > len(rows) {
|
||||
return nil, errors.New("not enough rows to return while parsing Tuple column")
|
||||
}
|
||||
ret := rows[i]
|
||||
i++
|
||||
return ret, nil
|
||||
}
|
||||
}(tupleRows)
|
||||
default:
|
||||
cd = func(decoder *binary.Decoder) columnDecoder {
|
||||
return func() (interface{}, error) { return array.column.Read(decoder, array.nullable) }
|
||||
}(decoder)
|
||||
}
|
||||
|
||||
// Read values
|
||||
for i := 0; i < rows; i++ {
|
||||
if values[i], err = array.read(cd, offsets, uint64(i), 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (array *Array) read(readColumn columnDecoder, offsets [][]uint64, index uint64, level int) (interface{}, error) {
|
||||
end := offsets[level][index]
|
||||
start := uint64(0)
|
||||
if index > 0 {
|
||||
start = offsets[level][index-1]
|
||||
}
|
||||
|
||||
scanT := array.column.ScanType()
|
||||
slice := reflect.MakeSlice(array.arrayType(level), 0, int(end-start))
|
||||
for i := start; i < end; i++ {
|
||||
var (
|
||||
value interface{}
|
||||
err error
|
||||
)
|
||||
if level == array.depth-1 {
|
||||
value, err = readColumn()
|
||||
} else {
|
||||
value, err = array.read(readColumn, offsets, i, level+1)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if array.nullable && level == array.depth-1 {
|
||||
f, ok := nullableAppender[scanT.String()]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(unsupportedArrayTypeErrTemp, scanT.String())
|
||||
}
|
||||
|
||||
cSlice, err := f(value, slice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slice = cSlice
|
||||
} else {
|
||||
slice = reflect.Append(slice, reflect.ValueOf(value))
|
||||
}
|
||||
|
||||
}
|
||||
return slice.Interface(), nil
|
||||
}
|
||||
|
||||
func (array *Array) arrayType(level int) reflect.Type {
|
||||
t := array.column.ScanType()
|
||||
for i := 0; i < array.depth-level; i++ {
|
||||
t = reflect.SliceOf(t)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (array *Array) Depth() int {
|
||||
return array.depth
|
||||
}
|
||||
|
||||
func parseArray(name, chType string, timezone *time.Location) (*Array, error) {
|
||||
if len(chType) < 11 {
|
||||
return nil, fmt.Errorf("invalid Array column type: %s", chType)
|
||||
}
|
||||
var (
|
||||
depth int
|
||||
columnType = chType
|
||||
)
|
||||
|
||||
loop:
|
||||
for _, str := range strings.Split(chType, "Array(") {
|
||||
switch {
|
||||
case len(str) == 0:
|
||||
depth++
|
||||
default:
|
||||
chType = str[:len(str)-depth]
|
||||
break loop
|
||||
}
|
||||
}
|
||||
column, err := Factory(name, chType, timezone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Array(T): %v", err)
|
||||
}
|
||||
|
||||
var scanType interface{}
|
||||
switch t := column.ScanType(); t {
|
||||
case arrayBaseTypes[int8(0)]:
|
||||
scanType = []int8{}
|
||||
case arrayBaseTypes[int16(0)]:
|
||||
scanType = []int16{}
|
||||
case arrayBaseTypes[int32(0)]:
|
||||
scanType = []int32{}
|
||||
case arrayBaseTypes[int64(0)]:
|
||||
scanType = []int64{}
|
||||
case arrayBaseTypes[uint8(0)]:
|
||||
scanType = []uint8{}
|
||||
case arrayBaseTypes[uint16(0)]:
|
||||
scanType = []uint16{}
|
||||
case arrayBaseTypes[uint32(0)]:
|
||||
scanType = []uint32{}
|
||||
case arrayBaseTypes[uint64(0)]:
|
||||
scanType = []uint64{}
|
||||
case arrayBaseTypes[float32(0)]:
|
||||
scanType = []float32{}
|
||||
case arrayBaseTypes[float64(0)]:
|
||||
scanType = []float64{}
|
||||
case arrayBaseTypes[string("")]:
|
||||
scanType = []string{}
|
||||
case arrayBaseTypes[time.Time{}]:
|
||||
scanType = []time.Time{}
|
||||
case arrayBaseTypes[IPv4{}], arrayBaseTypes[IPv6{}]:
|
||||
scanType = []net.IP{}
|
||||
case reflect.ValueOf([]interface{}{}).Type():
|
||||
scanType = [][]interface{}{}
|
||||
|
||||
//nullable
|
||||
case arrayBaseTypes[ptrInt8T]:
|
||||
scanType = []*int8{}
|
||||
case arrayBaseTypes[ptrInt16T]:
|
||||
scanType = []*int16{}
|
||||
case arrayBaseTypes[ptrInt32T]:
|
||||
scanType = []*int32{}
|
||||
case arrayBaseTypes[ptrInt64T]:
|
||||
scanType = []*int64{}
|
||||
case arrayBaseTypes[ptrUInt8T]:
|
||||
scanType = []*uint8{}
|
||||
case arrayBaseTypes[ptrUInt16T]:
|
||||
scanType = []*uint16{}
|
||||
case arrayBaseTypes[ptrUInt32T]:
|
||||
scanType = []*uint32{}
|
||||
case arrayBaseTypes[ptrUInt64T]:
|
||||
scanType = []*uint64{}
|
||||
case arrayBaseTypes[ptrFloat32]:
|
||||
scanType = []*float32{}
|
||||
case arrayBaseTypes[ptrFloat64]:
|
||||
scanType = []*float64{}
|
||||
case arrayBaseTypes[ptrString]:
|
||||
scanType = []*string{}
|
||||
case arrayBaseTypes[ptrTime]:
|
||||
scanType = []*time.Time{}
|
||||
case arrayBaseTypes[ptrIPv4], arrayBaseTypes[ptrIPv6]:
|
||||
scanType = []*net.IP{}
|
||||
default:
|
||||
return nil, fmt.Errorf(unsupportedArrayTypeErrTemp, column.ScanType().Name())
|
||||
}
|
||||
return &Array{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: columnType,
|
||||
valueOf: reflect.ValueOf(scanType),
|
||||
},
|
||||
depth: depth,
|
||||
column: column,
|
||||
nullable: strings.HasPrefix(column.CHType(), "Nullable"),
|
||||
}, nil
|
||||
}
|
||||
-205
@@ -1,205 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Column interface {
|
||||
Name() string
|
||||
CHType() string
|
||||
ScanType() reflect.Type
|
||||
Read(*binary.Decoder, bool) (interface{}, error)
|
||||
Write(*binary.Encoder, interface{}) error
|
||||
defaultValue() interface{}
|
||||
Depth() int
|
||||
}
|
||||
|
||||
func Factory(name, chType string, timezone *time.Location) (Column, error) {
|
||||
switch chType {
|
||||
case "Int8":
|
||||
return &Int8{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[int8(0)],
|
||||
},
|
||||
}, nil
|
||||
case "Int16":
|
||||
return &Int16{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[int16(0)],
|
||||
},
|
||||
}, nil
|
||||
case "Int32":
|
||||
return &Int32{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[int32(0)],
|
||||
},
|
||||
}, nil
|
||||
case "Int64":
|
||||
return &Int64{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[int64(0)],
|
||||
},
|
||||
}, nil
|
||||
case "UInt8":
|
||||
return &UInt8{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[uint8(0)],
|
||||
},
|
||||
}, nil
|
||||
case "UInt16":
|
||||
return &UInt16{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[uint16(0)],
|
||||
},
|
||||
}, nil
|
||||
case "UInt32":
|
||||
return &UInt32{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[uint32(0)],
|
||||
},
|
||||
}, nil
|
||||
case "UInt64":
|
||||
return &UInt64{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[uint64(0)],
|
||||
},
|
||||
}, nil
|
||||
case "Float32":
|
||||
return &Float32{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[float32(0)],
|
||||
},
|
||||
}, nil
|
||||
case "Float64":
|
||||
return &Float64{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[float64(0)],
|
||||
},
|
||||
}, nil
|
||||
case "String":
|
||||
return &String{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[string("")],
|
||||
},
|
||||
}, nil
|
||||
case "UUID":
|
||||
return &UUID{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[string("")],
|
||||
},
|
||||
}, nil
|
||||
case "Date":
|
||||
_, offset := time.Unix(0, 0).In(timezone).Zone()
|
||||
return &Date{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[time.Time{}],
|
||||
},
|
||||
Timezone: timezone,
|
||||
offset: int64(offset),
|
||||
}, nil
|
||||
case "IPv4":
|
||||
return &IPv4{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[IPv4{}],
|
||||
},
|
||||
}, nil
|
||||
case "IPv6":
|
||||
return &IPv6{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[IPv6{}],
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(chType, "DateTime") && !strings.HasPrefix(chType, "DateTime64"):
|
||||
return &DateTime{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: "DateTime",
|
||||
valueOf: columnBaseTypes[time.Time{}],
|
||||
},
|
||||
Timezone: timezone,
|
||||
}, nil
|
||||
case strings.HasPrefix(chType, "DateTime64"):
|
||||
return &DateTime64{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[time.Time{}],
|
||||
},
|
||||
Timezone: timezone,
|
||||
}, nil
|
||||
case strings.HasPrefix(chType, "Array"):
|
||||
return parseArray(name, chType, timezone)
|
||||
case strings.HasPrefix(chType, "Nullable"):
|
||||
return parseNullable(name, chType, timezone)
|
||||
case strings.HasPrefix(chType, "FixedString"):
|
||||
return parseFixedString(name, chType)
|
||||
case strings.HasPrefix(chType, "Enum8"), strings.HasPrefix(chType, "Enum16"):
|
||||
return parseEnum(name, chType)
|
||||
case strings.HasPrefix(chType, "Decimal"):
|
||||
return parseDecimal(name, chType)
|
||||
case strings.HasPrefix(chType, "SimpleAggregateFunction"):
|
||||
if nestedType, err := getNestedType(chType, "SimpleAggregateFunction"); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return Factory(name, nestedType, timezone)
|
||||
}
|
||||
case strings.HasPrefix(chType, "Tuple"):
|
||||
return parseTuple(name, chType, timezone)
|
||||
}
|
||||
return nil, fmt.Errorf("column: unhandled type %v", chType)
|
||||
}
|
||||
|
||||
func getNestedType(chType string, wrapType string) (string, error) {
|
||||
prefixLen := len(wrapType) + 1
|
||||
suffixLen := 1
|
||||
|
||||
if len(chType) > prefixLen+suffixLen {
|
||||
nested := strings.Split(chType[prefixLen:len(chType)-suffixLen], ",")
|
||||
if len(nested) == 2 {
|
||||
return strings.TrimSpace(nested[1]), nil
|
||||
}
|
||||
|
||||
if len(nested) == 3 {
|
||||
return strings.TrimSpace(strings.Join(nested[1:], ",")), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("column: invalid %s type (%s)", wrapType, chType)
|
||||
}
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ErrUnexpectedType struct {
|
||||
Column Column
|
||||
T interface{}
|
||||
}
|
||||
|
||||
func (err *ErrUnexpectedType) Error() string {
|
||||
return fmt.Sprintf("%s: unexpected type %T", err.Column, err.T)
|
||||
}
|
||||
|
||||
var columnBaseTypes = map[interface{}]reflect.Value{
|
||||
int8(0): reflect.ValueOf(int8(0)),
|
||||
int16(0): reflect.ValueOf(int16(0)),
|
||||
int32(0): reflect.ValueOf(int32(0)),
|
||||
int64(0): reflect.ValueOf(int64(0)),
|
||||
uint8(0): reflect.ValueOf(uint8(0)),
|
||||
uint16(0): reflect.ValueOf(uint16(0)),
|
||||
uint32(0): reflect.ValueOf(uint32(0)),
|
||||
uint64(0): reflect.ValueOf(uint64(0)),
|
||||
float32(0): reflect.ValueOf(float32(0)),
|
||||
float64(0): reflect.ValueOf(float64(0)),
|
||||
string(""): reflect.ValueOf(string("")),
|
||||
time.Time{}: reflect.ValueOf(time.Time{}),
|
||||
IPv4{}: reflect.ValueOf(net.IPv4zero),
|
||||
IPv6{}: reflect.ValueOf(net.IPv6unspecified),
|
||||
}
|
||||
|
||||
type ptrTo uint8
|
||||
|
||||
const (
|
||||
ptrInt8T ptrTo = iota
|
||||
ptrInt16T
|
||||
ptrInt32T
|
||||
ptrInt64T
|
||||
ptrUInt8T
|
||||
ptrUInt16T
|
||||
ptrUInt32T
|
||||
ptrUInt64T
|
||||
ptrFloat32
|
||||
ptrFloat64
|
||||
ptrString
|
||||
ptrTime
|
||||
ptrIPv4
|
||||
ptrIPv6
|
||||
)
|
||||
|
||||
var arrayBaseTypes = map[interface{}]reflect.Type{
|
||||
int8(0): reflect.ValueOf(int8(0)).Type(),
|
||||
int16(0): reflect.ValueOf(int16(0)).Type(),
|
||||
int32(0): reflect.ValueOf(int32(0)).Type(),
|
||||
int64(0): reflect.ValueOf(int64(0)).Type(),
|
||||
uint8(0): reflect.ValueOf(uint8(0)).Type(),
|
||||
uint16(0): reflect.ValueOf(uint16(0)).Type(),
|
||||
uint32(0): reflect.ValueOf(uint32(0)).Type(),
|
||||
uint64(0): reflect.ValueOf(uint64(0)).Type(),
|
||||
float32(0): reflect.ValueOf(float32(0)).Type(),
|
||||
float64(0): reflect.ValueOf(float64(0)).Type(),
|
||||
string(""): reflect.ValueOf(string("")).Type(),
|
||||
time.Time{}: reflect.ValueOf(time.Time{}).Type(),
|
||||
IPv4{}: reflect.ValueOf(net.IPv4zero).Type(),
|
||||
IPv6{}: reflect.ValueOf(net.IPv6unspecified).Type(),
|
||||
|
||||
// nullable
|
||||
ptrInt8T: reflect.PtrTo(reflect.ValueOf(int8(0)).Type()),
|
||||
ptrInt16T: reflect.PtrTo(reflect.ValueOf(int16(0)).Type()),
|
||||
ptrInt32T: reflect.PtrTo(reflect.ValueOf(int32(0)).Type()),
|
||||
ptrInt64T: reflect.PtrTo(reflect.ValueOf(int64(0)).Type()),
|
||||
ptrUInt8T: reflect.PtrTo(reflect.ValueOf(uint8(0)).Type()),
|
||||
ptrUInt16T: reflect.PtrTo(reflect.ValueOf(uint16(0)).Type()),
|
||||
ptrUInt32T: reflect.PtrTo(reflect.ValueOf(uint32(0)).Type()),
|
||||
ptrUInt64T: reflect.PtrTo(reflect.ValueOf(uint64(0)).Type()),
|
||||
ptrFloat32: reflect.PtrTo(reflect.ValueOf(float32(0)).Type()),
|
||||
ptrFloat64: reflect.PtrTo(reflect.ValueOf(float64(0)).Type()),
|
||||
ptrString: reflect.PtrTo(reflect.ValueOf(string("")).Type()),
|
||||
ptrTime: reflect.PtrTo(reflect.ValueOf(time.Time{}).Type()),
|
||||
ptrIPv4: reflect.PtrTo(reflect.ValueOf(net.IPv4zero).Type()),
|
||||
ptrIPv6: reflect.PtrTo(reflect.ValueOf(net.IPv6unspecified).Type()),
|
||||
}
|
||||
|
||||
type base struct {
|
||||
name, chType string
|
||||
valueOf reflect.Value
|
||||
}
|
||||
|
||||
func (base *base) Name() string {
|
||||
return base.name
|
||||
}
|
||||
|
||||
func (base *base) CHType() string {
|
||||
return base.chType
|
||||
}
|
||||
|
||||
func (base *base) ScanType() reflect.Type {
|
||||
return base.valueOf.Type()
|
||||
}
|
||||
|
||||
func (base *base) defaultValue() interface{} {
|
||||
return base.valueOf.Interface()
|
||||
}
|
||||
|
||||
func (base *base) String() string {
|
||||
return fmt.Sprintf("%s (%s)", base.name, base.chType)
|
||||
}
|
||||
|
||||
func (base *base) Depth() int {
|
||||
return 0
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Date struct {
|
||||
base
|
||||
Timezone *time.Location
|
||||
offset int64
|
||||
}
|
||||
|
||||
func (dt *Date) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
sec, err := decoder.Int16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return time.Unix(int64(sec)*24*3600-dt.offset, 0).In(dt.Timezone), nil
|
||||
}
|
||||
|
||||
func (dt *Date) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
var timestamp int64
|
||||
switch value := v.(type) {
|
||||
case time.Time:
|
||||
_, offset := value.Zone()
|
||||
timestamp = value.Unix() + int64(offset)
|
||||
case int16:
|
||||
return encoder.Int16(value)
|
||||
case int32:
|
||||
timestamp = int64(value) + dt.offset
|
||||
case uint32:
|
||||
timestamp = int64(value) + dt.offset
|
||||
case uint64:
|
||||
timestamp = int64(value) + dt.offset
|
||||
case int64:
|
||||
timestamp = value + dt.offset
|
||||
case string:
|
||||
var err error
|
||||
timestamp, err = dt.parse(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *time.Time:
|
||||
_, offset := value.Zone()
|
||||
timestamp = (*value).Unix() + int64(offset)
|
||||
case *int16:
|
||||
return encoder.Int16(*value)
|
||||
case *int32:
|
||||
timestamp = int64(*value) + dt.offset
|
||||
case *int64:
|
||||
timestamp = *value + dt.offset
|
||||
case *string:
|
||||
var err error
|
||||
timestamp, err = dt.parse(*value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: dt,
|
||||
}
|
||||
}
|
||||
|
||||
return encoder.Int16(int16(timestamp / 24 / 3600))
|
||||
}
|
||||
|
||||
func (dt *Date) parse(value string) (int64, error) {
|
||||
tv, err := time.Parse("2006-01-02", value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return time.Date(
|
||||
time.Time(tv).Year(),
|
||||
time.Time(tv).Month(),
|
||||
time.Time(tv).Day(),
|
||||
0, 0, 0, 0, time.UTC,
|
||||
).Unix(), nil
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type DateTime struct {
|
||||
base
|
||||
Timezone *time.Location
|
||||
}
|
||||
|
||||
func (dt *DateTime) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
sec, err := decoder.Int32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return time.Unix(int64(sec), 0).In(dt.Timezone), nil
|
||||
}
|
||||
|
||||
func (dt *DateTime) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
var timestamp int64
|
||||
switch value := v.(type) {
|
||||
case time.Time:
|
||||
if !value.IsZero() {
|
||||
timestamp = value.Unix()
|
||||
}
|
||||
case int16:
|
||||
timestamp = int64(value)
|
||||
case int32:
|
||||
timestamp = int64(value)
|
||||
case uint32:
|
||||
timestamp = int64(value)
|
||||
case uint64:
|
||||
timestamp = int64(value)
|
||||
case int64:
|
||||
timestamp = value
|
||||
case string:
|
||||
var err error
|
||||
timestamp, err = dt.parse(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *time.Time:
|
||||
if value != nil && !(*value).IsZero() {
|
||||
timestamp = (*value).Unix()
|
||||
}
|
||||
case *int16:
|
||||
timestamp = int64(*value)
|
||||
case *int32:
|
||||
timestamp = int64(*value)
|
||||
case *int64:
|
||||
timestamp = *value
|
||||
case *string:
|
||||
var err error
|
||||
timestamp, err = dt.parse(*value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: dt,
|
||||
}
|
||||
}
|
||||
|
||||
return encoder.Int32(int32(timestamp))
|
||||
}
|
||||
|
||||
func (dt *DateTime) parse(value string) (int64, error) {
|
||||
tv, err := time.Parse("2006-01-02 15:04:05", value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return time.Date(
|
||||
time.Time(tv).Year(),
|
||||
time.Time(tv).Month(),
|
||||
time.Time(tv).Day(),
|
||||
time.Time(tv).Hour(),
|
||||
time.Time(tv).Minute(),
|
||||
time.Time(tv).Second(),
|
||||
0, time.Local, //use local timzone when insert into clickhouse
|
||||
).Unix(), nil
|
||||
}
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type DateTime64 struct {
|
||||
base
|
||||
Timezone *time.Location
|
||||
}
|
||||
|
||||
func (dt *DateTime64) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
value, err := decoder.Int64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
precision, err := dt.getPrecision()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nano int64
|
||||
if precision < 19 {
|
||||
nano = value * int64(math.Pow10(9-precision))
|
||||
}
|
||||
|
||||
sec := nano / int64(10e8)
|
||||
nsec := nano - sec*10e8
|
||||
|
||||
return time.Unix(sec, nsec).In(dt.Timezone), nil
|
||||
}
|
||||
|
||||
func (dt *DateTime64) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
var timestamp int64
|
||||
switch value := v.(type) {
|
||||
case time.Time:
|
||||
if !value.IsZero() {
|
||||
timestamp = value.UnixNano()
|
||||
}
|
||||
case uint64:
|
||||
timestamp = int64(value)
|
||||
case int64:
|
||||
timestamp = value
|
||||
case string:
|
||||
var err error
|
||||
timestamp, err = dt.parse(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *time.Time:
|
||||
if value != nil && !(*value).IsZero() {
|
||||
timestamp = (*value).UnixNano()
|
||||
}
|
||||
case *int64:
|
||||
timestamp = *value
|
||||
case *string:
|
||||
var err error
|
||||
timestamp, err = dt.parse(*value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: dt,
|
||||
}
|
||||
}
|
||||
|
||||
precision, err := dt.getPrecision()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timestamp = timestamp / int64(math.Pow10(9-precision))
|
||||
|
||||
return encoder.Int64(timestamp)
|
||||
}
|
||||
|
||||
func (dt *DateTime64) parse(value string) (int64, error) {
|
||||
tv, err := time.Parse("2006-01-02 15:04:05.999", value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return tv.UnixNano(), nil
|
||||
}
|
||||
|
||||
func (dt *DateTime64) getPrecision() (int, error) {
|
||||
dtParams := dt.base.chType[11 : len(dt.base.chType)-1]
|
||||
precision, err := strconv.Atoi(strings.Split(dtParams, ",")[0])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return precision, nil
|
||||
}
|
||||
-377
@@ -1,377 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
b "encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
// Table of powers of 10 for fast casting from floating types to decimal type
|
||||
// representations.
|
||||
var factors10 = []float64{
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13,
|
||||
1e14, 1e15, 1e16, 1e17, 1e18,
|
||||
}
|
||||
|
||||
// Decimal represents Decimal(P, S) ClickHouse. Decimal is represented as
|
||||
// integral. Also floating-point types are supported for query parameters.
|
||||
//
|
||||
// Since there is no support for int128 in Golang, decimals with precision 19
|
||||
// through 38 are represented as 16 little-endian bytes.
|
||||
type Decimal struct {
|
||||
base
|
||||
nobits int // its domain is {32, 64}
|
||||
precision int
|
||||
scale int
|
||||
}
|
||||
|
||||
func (d *Decimal) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
switch d.nobits {
|
||||
case 32:
|
||||
return decoder.Int32()
|
||||
case 64:
|
||||
return decoder.Int64()
|
||||
case 128:
|
||||
return decoder.Decimal128()
|
||||
default:
|
||||
return nil, errors.New("unachievable execution path")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decimal) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch d.nobits {
|
||||
case 32:
|
||||
return d.write32(encoder, v)
|
||||
case 64:
|
||||
return d.write64(encoder, v)
|
||||
case 128:
|
||||
return d.write128(encoder, v)
|
||||
default:
|
||||
return errors.New("unachievable execution path")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decimal) float2int32(floating float64) int32 {
|
||||
fixed := int32(floating * factors10[d.scale])
|
||||
return fixed
|
||||
}
|
||||
|
||||
func (d *Decimal) float2int64(floating float64) int64 {
|
||||
fixed := int64(floating * factors10[d.scale])
|
||||
return fixed
|
||||
}
|
||||
|
||||
func (d *Decimal) write32(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int8:
|
||||
return encoder.Int32(int32(v))
|
||||
case int16:
|
||||
return encoder.Int32(int32(v))
|
||||
case int32:
|
||||
return encoder.Int32(int32(v))
|
||||
case int64:
|
||||
if v > math.MaxInt32 || v < math.MinInt32 {
|
||||
return errors.New("overflow when narrowing type conversion from int64 to int32")
|
||||
}
|
||||
return encoder.Int32(int32(v))
|
||||
|
||||
case uint8:
|
||||
return encoder.Int32(int32(v))
|
||||
case uint16:
|
||||
return encoder.Int32(int32(v))
|
||||
case uint32:
|
||||
if v > math.MaxInt32 {
|
||||
return errors.New("overflow when narrowing type conversion from uint32 to int32")
|
||||
}
|
||||
return encoder.Int32(int32(v))
|
||||
case uint64:
|
||||
if v > math.MaxInt32 {
|
||||
return errors.New("overflow when narrowing type conversion from uint64 to int32")
|
||||
}
|
||||
return encoder.Int32(int32(v))
|
||||
|
||||
case float32:
|
||||
fixed := d.float2int32(float64(v))
|
||||
return encoder.Int32(fixed)
|
||||
case float64:
|
||||
fixed := d.float2int32(float64(v))
|
||||
return encoder.Int32(fixed)
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int8:
|
||||
return encoder.Int32(int32(*v))
|
||||
case *int16:
|
||||
return encoder.Int32(int32(*v))
|
||||
case *int32:
|
||||
return encoder.Int32(int32(*v))
|
||||
case *int64:
|
||||
if *v > math.MaxInt32 || *v < math.MinInt32 {
|
||||
return errors.New("overflow when narrowing type conversion from int64 to int32")
|
||||
}
|
||||
return encoder.Int32(int32(*v))
|
||||
|
||||
case *uint8:
|
||||
return encoder.Int32(int32(*v))
|
||||
case *uint16:
|
||||
return encoder.Int32(int32(*v))
|
||||
case *uint32:
|
||||
if *v > math.MaxInt32 {
|
||||
return errors.New("overflow when narrowing type conversion from uint34 to int32")
|
||||
}
|
||||
return encoder.Int32(int32(*v))
|
||||
case *uint64:
|
||||
if *v > math.MaxInt32 {
|
||||
return errors.New("overflow when narrowing type conversion from uint64 to int32")
|
||||
}
|
||||
return encoder.Int32(int32(*v))
|
||||
|
||||
case *float32:
|
||||
fixed := d.float2int32(float64(*v))
|
||||
return encoder.Int32(fixed)
|
||||
case *float64:
|
||||
fixed := d.float2int32(float64(*v))
|
||||
return encoder.Int32(fixed)
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decimal) write64(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
return encoder.Int64(int64(v))
|
||||
case int8:
|
||||
return encoder.Int64(int64(v))
|
||||
case int16:
|
||||
return encoder.Int64(int64(v))
|
||||
case int32:
|
||||
return encoder.Int64(int64(v))
|
||||
case int64:
|
||||
return encoder.Int64(int64(v))
|
||||
|
||||
case uint8:
|
||||
return encoder.Int64(int64(v))
|
||||
case uint16:
|
||||
return encoder.Int64(int64(v))
|
||||
case uint32:
|
||||
return encoder.Int64(int64(v))
|
||||
case uint64:
|
||||
if v > math.MaxInt64 {
|
||||
return errors.New("overflow when narrowing type conversion from uint64 to int64")
|
||||
}
|
||||
return encoder.Int64(int64(v))
|
||||
|
||||
case float32:
|
||||
fixed := d.float2int64(float64(v))
|
||||
return encoder.Int64(fixed)
|
||||
case float64:
|
||||
fixed := d.float2int64(float64(v))
|
||||
return encoder.Int64(fixed)
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *int8:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *int16:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *int32:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *int64:
|
||||
return encoder.Int64(int64(*v))
|
||||
|
||||
case *uint8:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *uint16:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *uint32:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *uint64:
|
||||
if *v > math.MaxInt64 {
|
||||
return errors.New("overflow when narrowing type conversion from uint64 to int64")
|
||||
}
|
||||
return encoder.Int64(int64(*v))
|
||||
|
||||
case *float32:
|
||||
fixed := d.float2int64(float64(*v))
|
||||
return encoder.Int64(fixed)
|
||||
case *float64:
|
||||
fixed := d.float2int64(float64(*v))
|
||||
return encoder.Int64(fixed)
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: d,
|
||||
}
|
||||
}
|
||||
|
||||
// Turns an int64 into 16 little-endian bytes.
|
||||
func int64ToDecimal128(v int64) []byte {
|
||||
bytes := make([]byte, 16)
|
||||
b.LittleEndian.PutUint64(bytes[:8], uint64(v))
|
||||
sign := 0
|
||||
if v < 0 {
|
||||
sign = -1
|
||||
}
|
||||
b.LittleEndian.PutUint64(bytes[8:], uint64(sign))
|
||||
return bytes
|
||||
}
|
||||
|
||||
// Turns a uint64 into 16 little-endian bytes.
|
||||
func uint64ToDecimal128(v uint64) []byte {
|
||||
bytes := make([]byte, 16)
|
||||
b.LittleEndian.PutUint64(bytes[:8], uint64(v))
|
||||
return bytes
|
||||
}
|
||||
|
||||
func (d *Decimal) write128(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(v)))
|
||||
case int8:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(v)))
|
||||
case int16:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(v)))
|
||||
case int32:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(v)))
|
||||
case int64:
|
||||
return encoder.Decimal128(int64ToDecimal128(v))
|
||||
|
||||
case uint8:
|
||||
return encoder.Decimal128(uint64ToDecimal128(uint64(v)))
|
||||
case uint16:
|
||||
return encoder.Decimal128(uint64ToDecimal128(uint64(v)))
|
||||
case uint32:
|
||||
return encoder.Decimal128(uint64ToDecimal128(uint64(v)))
|
||||
case uint64:
|
||||
return encoder.Decimal128(uint64ToDecimal128(v))
|
||||
|
||||
case float32:
|
||||
fixed := d.float2int64(float64(v))
|
||||
return encoder.Decimal128(int64ToDecimal128(fixed))
|
||||
case float64:
|
||||
fixed := d.float2int64(float64(v))
|
||||
return encoder.Decimal128(int64ToDecimal128(fixed))
|
||||
|
||||
case []byte:
|
||||
if len(v) != 16 {
|
||||
return errors.New("expected 16 bytes")
|
||||
}
|
||||
return encoder.Decimal128(v)
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(*v)))
|
||||
case *int8:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(*v)))
|
||||
case *int16:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(*v)))
|
||||
case *int32:
|
||||
return encoder.Decimal128(int64ToDecimal128(int64(*v)))
|
||||
case *int64:
|
||||
return encoder.Decimal128(int64ToDecimal128(*v))
|
||||
|
||||
case *uint8:
|
||||
return encoder.Decimal128(uint64ToDecimal128(uint64(*v)))
|
||||
case *uint16:
|
||||
return encoder.Decimal128(uint64ToDecimal128(uint64(*v)))
|
||||
case *uint32:
|
||||
return encoder.Decimal128(uint64ToDecimal128(uint64(*v)))
|
||||
case *uint64:
|
||||
return encoder.Decimal128(uint64ToDecimal128(*v))
|
||||
|
||||
case *float32:
|
||||
fixed := d.float2int64(float64(*v))
|
||||
return encoder.Decimal128(int64ToDecimal128(fixed))
|
||||
case *float64:
|
||||
fixed := d.float2int64(float64(*v))
|
||||
return encoder.Decimal128(int64ToDecimal128(fixed))
|
||||
|
||||
case *[]byte:
|
||||
if len(*v) != 16 {
|
||||
return errors.New("expected 16 bytes")
|
||||
}
|
||||
return encoder.Decimal128(*v)
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: d,
|
||||
}
|
||||
}
|
||||
|
||||
func parseDecimal(name, chType string) (Column, error) {
|
||||
switch {
|
||||
case len(chType) < 12:
|
||||
fallthrough
|
||||
case !strings.HasPrefix(chType, "Decimal"):
|
||||
fallthrough
|
||||
case chType[7] != '(':
|
||||
fallthrough
|
||||
case chType[len(chType)-1] != ')':
|
||||
return nil, fmt.Errorf("invalid Decimal format: '%s'", chType)
|
||||
}
|
||||
|
||||
var params = strings.Split(chType[8:len(chType)-1], ",")
|
||||
|
||||
if len(params) != 2 {
|
||||
return nil, fmt.Errorf("invalid Decimal format: '%s'", chType)
|
||||
}
|
||||
|
||||
params[0] = strings.TrimSpace(params[0])
|
||||
params[1] = strings.TrimSpace(params[1])
|
||||
|
||||
var err error
|
||||
var decimal = &Decimal{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
},
|
||||
}
|
||||
|
||||
if decimal.precision, err = strconv.Atoi(params[0]); err != nil {
|
||||
return nil, fmt.Errorf("'%s' is not Decimal type: %s", chType, err)
|
||||
} else if decimal.precision < 1 {
|
||||
return nil, errors.New("wrong precision of Decimal type")
|
||||
}
|
||||
|
||||
if decimal.scale, err = strconv.Atoi(params[1]); err != nil {
|
||||
return nil, fmt.Errorf("'%s' is not Decimal type: %s", chType, err)
|
||||
} else if decimal.scale < 0 || decimal.scale > decimal.precision {
|
||||
return nil, errors.New("wrong scale of Decimal type")
|
||||
}
|
||||
|
||||
switch {
|
||||
case decimal.precision <= 9:
|
||||
decimal.nobits = 32
|
||||
decimal.valueOf = columnBaseTypes[int32(0)]
|
||||
case decimal.precision <= 18:
|
||||
decimal.nobits = 64
|
||||
decimal.valueOf = columnBaseTypes[int64(0)]
|
||||
case decimal.precision <= 38:
|
||||
decimal.nobits = 128
|
||||
decimal.valueOf = reflect.ValueOf([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
default:
|
||||
return nil, errors.New("precision of Decimal exceeds max bound")
|
||||
}
|
||||
|
||||
return decimal, nil
|
||||
}
|
||||
|
||||
func (d *Decimal) GetPrecision() int {
|
||||
return d.precision
|
||||
}
|
||||
|
||||
func (d *Decimal) GetScale() int {
|
||||
return d.scale
|
||||
}
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Enum struct {
|
||||
iv map[string]interface{}
|
||||
vi map[interface{}]string
|
||||
base
|
||||
baseType interface{}
|
||||
}
|
||||
|
||||
func (enum *Enum) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
var (
|
||||
err error
|
||||
ident interface{}
|
||||
)
|
||||
switch enum.baseType.(type) {
|
||||
case int16:
|
||||
if ident, err = decoder.Int16(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
if ident, err = decoder.Int8(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if ident, found := enum.vi[ident]; found || isNull {
|
||||
return ident, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid Enum value: %v", ident)
|
||||
}
|
||||
|
||||
func (enum *Enum) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return enum.encodeFromString(v, encoder)
|
||||
case uint8:
|
||||
if _, ok := enum.baseType.(int8); ok {
|
||||
return encoder.Int8(int8(v))
|
||||
}
|
||||
case int8:
|
||||
if _, ok := enum.baseType.(int8); ok {
|
||||
return encoder.Int8(v)
|
||||
}
|
||||
case uint16:
|
||||
if _, ok := enum.baseType.(int16); ok {
|
||||
return encoder.Int16(int16(v))
|
||||
}
|
||||
case int16:
|
||||
if _, ok := enum.baseType.(int16); ok {
|
||||
return encoder.Int16(v)
|
||||
}
|
||||
case int64:
|
||||
switch enum.baseType.(type) {
|
||||
case int8:
|
||||
return encoder.Int8(int8(v))
|
||||
case int16:
|
||||
return encoder.Int16(int16(v))
|
||||
}
|
||||
// nullable enums
|
||||
case *string:
|
||||
return enum.encodeFromString(*v, encoder)
|
||||
case *uint8:
|
||||
if _, ok := enum.baseType.(int8); ok {
|
||||
return encoder.Int8(int8(*v))
|
||||
}
|
||||
case *int8:
|
||||
if _, ok := enum.baseType.(int8); ok {
|
||||
return encoder.Int8(*v)
|
||||
}
|
||||
case *uint16:
|
||||
if _, ok := enum.baseType.(int16); ok {
|
||||
return encoder.Int16(int16(*v))
|
||||
}
|
||||
case *int16:
|
||||
if _, ok := enum.baseType.(int16); ok {
|
||||
return encoder.Int16(*v)
|
||||
}
|
||||
case *int64:
|
||||
switch enum.baseType.(type) {
|
||||
case int8:
|
||||
return encoder.Int8(int8(*v))
|
||||
case int16:
|
||||
return encoder.Int16(int16(*v))
|
||||
}
|
||||
}
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: enum,
|
||||
}
|
||||
}
|
||||
|
||||
func (enum *Enum) encodeFromString(v string, encoder *binary.Encoder) error {
|
||||
ident, found := enum.iv[v]
|
||||
if !found {
|
||||
return fmt.Errorf("invalid Enum ident: %s", v)
|
||||
}
|
||||
switch ident := ident.(type) {
|
||||
case int8:
|
||||
return encoder.Int8(ident)
|
||||
case int16:
|
||||
return encoder.Int16(ident)
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: ident,
|
||||
Column: enum,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (enum *Enum) defaultValue() interface{} {
|
||||
return enum.baseType
|
||||
}
|
||||
|
||||
func parseEnum(name, chType string) (*Enum, error) {
|
||||
var (
|
||||
data string
|
||||
isEnum16 bool
|
||||
)
|
||||
if len(chType) < 8 {
|
||||
return nil, fmt.Errorf("invalid Enum format: %s", chType)
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(chType, "Enum8"):
|
||||
data = chType[6:]
|
||||
case strings.HasPrefix(chType, "Enum16"):
|
||||
data = chType[7:]
|
||||
isEnum16 = true
|
||||
default:
|
||||
return nil, fmt.Errorf("'%s' is not Enum type", chType)
|
||||
}
|
||||
enum := Enum{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[string("")],
|
||||
},
|
||||
iv: make(map[string]interface{}),
|
||||
vi: make(map[interface{}]string),
|
||||
}
|
||||
for _, block := range strings.Split(data[:len(data)-1], ",") {
|
||||
parts := strings.Split(block, "=")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid Enum format: %s", chType)
|
||||
}
|
||||
var (
|
||||
ident = strings.TrimSpace(parts[0])
|
||||
value, err = strconv.ParseInt(strings.TrimSpace(parts[1]), 10, 16)
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid Enum value: %v", chType)
|
||||
}
|
||||
{
|
||||
var (
|
||||
ident = ident[1 : len(ident)-1]
|
||||
value interface{} = int16(value)
|
||||
)
|
||||
if !isEnum16 {
|
||||
value = int8(value.(int16))
|
||||
}
|
||||
if enum.baseType == nil {
|
||||
enum.baseType = value
|
||||
}
|
||||
enum.iv[ident] = value
|
||||
enum.vi[value] = ident
|
||||
}
|
||||
}
|
||||
return &enum, nil
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type FixedString struct {
|
||||
base
|
||||
len int
|
||||
scanType reflect.Type
|
||||
}
|
||||
|
||||
func (str *FixedString) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Fixed(str.len)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(v), nil
|
||||
}
|
||||
|
||||
func (str *FixedString) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
var fixedString []byte
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
fixedString = binary.Str2Bytes(v)
|
||||
case []byte:
|
||||
fixedString = v
|
||||
case encoding.BinaryMarshaler:
|
||||
bytes, err := v.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fixedString = bytes
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: str,
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case len(fixedString) > str.len:
|
||||
return fmt.Errorf("too large value '%s' (expected %d, got %d)", fixedString, str.len, len(fixedString))
|
||||
case len(fixedString) < str.len:
|
||||
tmp := make([]byte, str.len)
|
||||
copy(tmp, fixedString)
|
||||
fixedString = tmp
|
||||
}
|
||||
if _, err := encoder.Write(fixedString); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseFixedString(name, chType string) (*FixedString, error) {
|
||||
var strLen int
|
||||
if _, err := fmt.Sscanf(chType, "FixedString(%d)", &strLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FixedString{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
valueOf: columnBaseTypes[string("")],
|
||||
},
|
||||
len: strLen,
|
||||
}, nil
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Float32 struct{ base }
|
||||
|
||||
func (Float32) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Float32()
|
||||
if err != nil {
|
||||
return float32(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (float *Float32) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case float32:
|
||||
return encoder.Float32(v)
|
||||
case float64:
|
||||
return encoder.Float32(float32(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *float32:
|
||||
return encoder.Float32(*v)
|
||||
case *float64:
|
||||
return encoder.Float32(float32(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: float,
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Float64 struct{ base }
|
||||
|
||||
func (Float64) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Float64()
|
||||
if err != nil {
|
||||
return float64(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (float *Float64) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case float32:
|
||||
return encoder.Float64(float64(v))
|
||||
case float64:
|
||||
return encoder.Float64(v)
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *float32:
|
||||
return encoder.Float64(float64(*v))
|
||||
case *float64:
|
||||
return encoder.Float64(*v)
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: float,
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Int16 struct{ base }
|
||||
|
||||
func (Int16) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Int16()
|
||||
if err != nil {
|
||||
return int16(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *Int16) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int16:
|
||||
return encoder.Int16(v)
|
||||
case int64:
|
||||
return encoder.Int16(int16(v))
|
||||
case int:
|
||||
return encoder.Int16(int16(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int16:
|
||||
return encoder.Int16(*v)
|
||||
case *int64:
|
||||
return encoder.Int16(int16(*v))
|
||||
case *int:
|
||||
return encoder.Int16(int16(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: i,
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Int32 struct{ base }
|
||||
|
||||
func (Int32) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Int32()
|
||||
if err != nil {
|
||||
return int32(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *Int32) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int32:
|
||||
return encoder.Int32(v)
|
||||
case int64:
|
||||
return encoder.Int32(int32(v))
|
||||
case int:
|
||||
return encoder.Int32(int32(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int32:
|
||||
return encoder.Int32(*v)
|
||||
case *int64:
|
||||
return encoder.Int32(int32(*v))
|
||||
case *int:
|
||||
return encoder.Int32(int32(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: i,
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Int64 struct{ base }
|
||||
|
||||
func (Int64) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Int64()
|
||||
if err != nil {
|
||||
return int64(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *Int64) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
return encoder.Int64(int64(v))
|
||||
case int64:
|
||||
return encoder.Int64(v)
|
||||
case []byte:
|
||||
if _, err := encoder.Write(v); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int:
|
||||
return encoder.Int64(int64(*v))
|
||||
case *int64:
|
||||
return encoder.Int64(*v)
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: i,
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Int8 struct{ base }
|
||||
|
||||
func (Int8) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Int8()
|
||||
if err != nil {
|
||||
return int8(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (i *Int8) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case int8:
|
||||
return encoder.Int8(v)
|
||||
case int64:
|
||||
return encoder.Int8(int8(v))
|
||||
case int:
|
||||
return encoder.Int8(int8(v))
|
||||
case bool:
|
||||
if v {
|
||||
return encoder.Int8(int8(1))
|
||||
}
|
||||
return encoder.Int8(int8(0))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *int8:
|
||||
return encoder.Int8(*v)
|
||||
case *int64:
|
||||
return encoder.Int8(int8(*v))
|
||||
case *int:
|
||||
return encoder.Int8(int8(*v))
|
||||
case *bool:
|
||||
if *v {
|
||||
return encoder.Int8(int8(1))
|
||||
}
|
||||
return encoder.Int8(int8(0))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: i,
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
IP type supporting for clickhouse as FixedString(16)
|
||||
*/
|
||||
|
||||
package column
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidScanType = errors.New("Invalid scan types")
|
||||
errInvalidScanValue = errors.New("Invalid scan value")
|
||||
)
|
||||
|
||||
// IP column type
|
||||
type IP net.IP
|
||||
|
||||
// Value implements the driver.Valuer interface, json field interface
|
||||
// Alignment on the right side
|
||||
func (ip IP) Value() (driver.Value, error) {
|
||||
return ip.MarshalBinary()
|
||||
}
|
||||
|
||||
func (ip IP) MarshalBinary() ([]byte, error) {
|
||||
if len(ip) < 16 {
|
||||
var (
|
||||
buff = make([]byte, 16)
|
||||
j = 0
|
||||
)
|
||||
for i := 16 - len(ip); i < 16; i++ {
|
||||
buff[i] = ip[j]
|
||||
j++
|
||||
}
|
||||
for i := 0; i < 16-len(ip); i++ {
|
||||
buff[i] = '\x00'
|
||||
}
|
||||
if len(ip) == 4 {
|
||||
buff[11] = '\xff'
|
||||
buff[10] = '\xff'
|
||||
}
|
||||
return buff, nil
|
||||
}
|
||||
return []byte(ip), nil
|
||||
}
|
||||
|
||||
// Scan implements the driver.Valuer interface, json field interface
|
||||
func (ip *IP) Scan(value interface{}) (err error) {
|
||||
switch v := value.(type) {
|
||||
case []byte:
|
||||
if len(v) == 4 || len(v) == 16 {
|
||||
*ip = IP(v)
|
||||
} else {
|
||||
err = errInvalidScanValue
|
||||
}
|
||||
case string:
|
||||
if v == "" {
|
||||
err = errInvalidScanValue
|
||||
return
|
||||
}
|
||||
if (len(v) == 4 || len(v) == 16) && !strings.Contains(v, ".") && !strings.Contains(v, ":"){
|
||||
*ip = IP([]byte(v))
|
||||
return
|
||||
}
|
||||
if strings.Contains(v, ":") {
|
||||
*ip = IP(net.ParseIP(v))
|
||||
return
|
||||
}
|
||||
*ip = IP(net.ParseIP(v).To4())
|
||||
case net.IP:
|
||||
*ip = IP(v)
|
||||
default:
|
||||
err = errInvalidScanType
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (ip IP) String() string {
|
||||
return net.IP(ip).String()
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type IPv4 struct {
|
||||
base
|
||||
}
|
||||
|
||||
func (*IPv4) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Fixed(4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return net.IPv4(v[3], v[2], v[1], v[0]), nil
|
||||
}
|
||||
|
||||
func (ip *IPv4) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
var netIP net.IP
|
||||
switch v.(type) {
|
||||
case string:
|
||||
netIP = net.ParseIP(v.(string))
|
||||
case net.IP:
|
||||
netIP = v.(net.IP)
|
||||
case *net.IP:
|
||||
netIP = *(v.(*net.IP))
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: ip,
|
||||
}
|
||||
}
|
||||
|
||||
if netIP == nil {
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: ip,
|
||||
}
|
||||
}
|
||||
ip4 := netIP.To4()
|
||||
if ip4 == nil {
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: ip,
|
||||
}
|
||||
}
|
||||
if _, err := encoder.Write([]byte{ip4[3], ip4[2], ip4[1], ip4[0]}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type IPv6 struct {
|
||||
base
|
||||
}
|
||||
|
||||
func (*IPv6) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.Fixed(16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return net.IP(v), nil
|
||||
}
|
||||
|
||||
func (ip *IPv6) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
var netIP net.IP
|
||||
switch v.(type) {
|
||||
case string:
|
||||
netIP = net.ParseIP(v.(string))
|
||||
case net.IP:
|
||||
netIP = v.(net.IP)
|
||||
case *net.IP:
|
||||
netIP = *(v.(*net.IP))
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: ip,
|
||||
}
|
||||
}
|
||||
|
||||
if netIP == nil {
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: ip,
|
||||
}
|
||||
}
|
||||
if _, err := encoder.Write([]byte(netIP.To16())); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type Nullable struct {
|
||||
base
|
||||
column Column
|
||||
}
|
||||
|
||||
func (null *Nullable) ScanType() reflect.Type {
|
||||
return reflect.PtrTo(null.column.ScanType())
|
||||
}
|
||||
|
||||
func (null *Nullable) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
return null.column.Read(decoder, isNull)
|
||||
}
|
||||
|
||||
func (null *Nullable) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (null *Nullable) ReadNull(decoder *binary.Decoder, rows int) (_ []interface{}, err error) {
|
||||
var (
|
||||
isNull byte
|
||||
value interface{}
|
||||
nulls = make([]byte, rows)
|
||||
values = make([]interface{}, rows)
|
||||
)
|
||||
for i := 0; i < rows; i++ {
|
||||
if isNull, err = decoder.ReadByte(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nulls[i] = isNull
|
||||
}
|
||||
for i, isNull := range nulls {
|
||||
switch value, err = null.column.Read(decoder, isNull != 0); true {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
case isNull == 0:
|
||||
values[i] = value
|
||||
default:
|
||||
values[i] = nil
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
func (null *Nullable) WriteNull(nulls, encoder *binary.Encoder, v interface{}) error {
|
||||
if isNil(v) {
|
||||
if _, err := nulls.Write([]byte{1}); err != nil {
|
||||
return err
|
||||
}
|
||||
return null.column.Write(encoder, null.column.defaultValue())
|
||||
}
|
||||
if _, err := nulls.Write([]byte{0}); err != nil {
|
||||
return err
|
||||
}
|
||||
return null.column.Write(encoder, v)
|
||||
}
|
||||
|
||||
func parseNullable(name, chType string, timezone *time.Location) (*Nullable, error) {
|
||||
if len(chType) < 14 {
|
||||
return nil, fmt.Errorf("invalid Nullable column type: %s", chType)
|
||||
}
|
||||
column, err := Factory(name, chType[9:][:len(chType)-10], timezone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Nullable(T): %v", err)
|
||||
}
|
||||
return &Nullable{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: chType,
|
||||
},
|
||||
column: column,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (null *Nullable) GetColumn() Column {
|
||||
return null.column
|
||||
}
|
||||
|
||||
func isNil(v interface{}) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
switch val := reflect.ValueOf(v); val.Type().Kind() {
|
||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return val.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
|
||||
// DANGER! This code was autogenerated from template by clickhouse-go/lib/codegen/nullable_appender.
|
||||
// You shouldn't change it manually.
|
||||
// For more info check clickhouse-go/lib/codegen/nullable_appender/main.go
|
||||
|
||||
package column
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var nullableAppender = map[string]func(v interface{}, slice reflect.Value) (reflect.Value, error){
|
||||
|
||||
"*int8": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(int8)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type int8")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *int8
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*int16": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(int16)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type int16")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *int16
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*int32": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(int32)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type int32")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *int32
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*int64": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(int64)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type int64")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *int64
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*uint8": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(uint8)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type uint8")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *uint8
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*uint16": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(uint16)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type uint16")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *uint16
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*uint32": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(uint32)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type uint32")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *uint32
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*uint64": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(uint64)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type uint64")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *uint64
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*float32": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(float32)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type float32")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *float32
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*float64": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(float64)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type float64")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *float64
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*string": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(string)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type string")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *string
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*time.Time": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(time.Time)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type time.Time")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *time.Time
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
"*net.IP": func(v interface{}, slice reflect.Value) (reflect.Value, error) {
|
||||
if v != nil {
|
||||
v, ok := v.(net.IP)
|
||||
if !ok {
|
||||
return slice, fmt.Errorf("cannot assert to type net.IP")
|
||||
}
|
||||
return reflect.Append(slice, reflect.ValueOf(&v)), nil
|
||||
}
|
||||
var vNil *net.IP
|
||||
return reflect.Append(slice, reflect.ValueOf(vNil)), nil
|
||||
},
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type String struct{ base }
|
||||
|
||||
func (String) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.String()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (str *String) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return encoder.String(v)
|
||||
case []byte:
|
||||
return encoder.RawString(v)
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *string:
|
||||
return encoder.String(*v)
|
||||
case *[]byte:
|
||||
return encoder.RawString(*v)
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: str,
|
||||
}
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Tuple struct {
|
||||
base
|
||||
columns []Column
|
||||
}
|
||||
|
||||
func (tuple *Tuple) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
return nil, fmt.Errorf("do not use Read method for Tuple(T) column")
|
||||
}
|
||||
|
||||
func (tuple *Tuple) ReadTuple(decoder *binary.Decoder, rows int) ([]interface{}, error) {
|
||||
var values = make([][]interface{}, rows)
|
||||
|
||||
for _, c := range tuple.columns {
|
||||
|
||||
switch column := c.(type) {
|
||||
case *Array:
|
||||
cols, err := column.ReadArray(decoder, rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < rows; i++ {
|
||||
values[i] = append(values[i], cols[i])
|
||||
}
|
||||
|
||||
case *Nullable:
|
||||
cols, err := column.ReadNull(decoder, rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < rows; i++ {
|
||||
values[i] = append(values[i], cols[i])
|
||||
}
|
||||
|
||||
case *Tuple:
|
||||
cols, err := column.ReadTuple(decoder, rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < rows; i++ {
|
||||
values[i] = append(values[i], cols[i])
|
||||
}
|
||||
|
||||
default:
|
||||
for i := 0; i < rows; i++ {
|
||||
value, err := c.Read(decoder, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[i] = append(values[i], value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ret = make([]interface{}, rows)
|
||||
for i := range values {
|
||||
ret[i] = values[i]
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (tuple *Tuple) Write(encoder *binary.Encoder, v interface{}) (err error) {
|
||||
return fmt.Errorf("unsupported Tuple(T) type [%T]", v)
|
||||
}
|
||||
|
||||
func parseTuple(name, chType string, timezone *time.Location) (Column, error) {
|
||||
var columnType = chType
|
||||
|
||||
chType = chType[6 : len(chType)-1]
|
||||
var types []string
|
||||
var last, diff int
|
||||
for i, b := range chType + "," {
|
||||
if b == '(' {
|
||||
diff++
|
||||
} else if b == ')' {
|
||||
diff--
|
||||
} else if b == ',' && diff == 0 {
|
||||
types = append(types, chType[last:i])
|
||||
last = i + 2
|
||||
}
|
||||
}
|
||||
|
||||
var columns = make([]Column, 0, len(types))
|
||||
for i, chType := range types {
|
||||
column, err := Factory(name+"."+strconv.Itoa(i+1), chType, timezone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %v", chType, err)
|
||||
}
|
||||
columns = append(columns, column)
|
||||
}
|
||||
|
||||
return &Tuple{
|
||||
base: base{
|
||||
name: name,
|
||||
chType: columnType,
|
||||
valueOf: reflect.ValueOf([]interface{}{}),
|
||||
},
|
||||
columns: columns,
|
||||
}, nil
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type UInt16 struct{ base }
|
||||
|
||||
func (UInt16) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.UInt16()
|
||||
if err != nil {
|
||||
return uint16(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (u *UInt16) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case uint16:
|
||||
return encoder.UInt16(v)
|
||||
case int64:
|
||||
return encoder.UInt16(uint16(v))
|
||||
case uint64:
|
||||
return encoder.UInt16(uint16(v))
|
||||
case int:
|
||||
return encoder.UInt16(uint16(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *uint16:
|
||||
return encoder.UInt16(*v)
|
||||
case *int64:
|
||||
return encoder.UInt16(uint16(*v))
|
||||
case *uint64:
|
||||
return encoder.UInt16(uint16(*v))
|
||||
case *int:
|
||||
return encoder.UInt16(uint16(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: u,
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type UInt32 struct{ base }
|
||||
|
||||
func (UInt32) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.UInt32()
|
||||
if err != nil {
|
||||
return uint32(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (u *UInt32) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case uint32:
|
||||
return encoder.UInt32(v)
|
||||
case uint64:
|
||||
return encoder.UInt32(uint32(v))
|
||||
case int64:
|
||||
return encoder.UInt32(uint32(v))
|
||||
case int:
|
||||
return encoder.UInt32(uint32(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *uint64:
|
||||
return encoder.UInt32(uint32(*v))
|
||||
case *uint32:
|
||||
return encoder.UInt32(*v)
|
||||
case *int64:
|
||||
return encoder.UInt32(uint32(*v))
|
||||
case *int:
|
||||
return encoder.UInt32(uint32(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: u,
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type UInt64 struct{ base }
|
||||
|
||||
func (UInt64) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.UInt64()
|
||||
if err != nil {
|
||||
return uint64(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (u *UInt64) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case []byte:
|
||||
if _, err := encoder.Write(v); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case uint64:
|
||||
return encoder.UInt64(v)
|
||||
case int64:
|
||||
return encoder.UInt64(uint64(v))
|
||||
case int:
|
||||
return encoder.UInt64(uint64(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *uint64:
|
||||
return encoder.UInt64(*v)
|
||||
case *int64:
|
||||
return encoder.UInt64(uint64(*v))
|
||||
case *int:
|
||||
return encoder.UInt64(uint64(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: u,
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
type UInt8 struct{ base }
|
||||
|
||||
func (UInt8) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
v, err := decoder.UInt8()
|
||||
if err != nil {
|
||||
return uint8(0), err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (u *UInt8) Write(encoder *binary.Encoder, v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case bool:
|
||||
return encoder.Bool(v)
|
||||
case uint8:
|
||||
return encoder.UInt8(v)
|
||||
case int64:
|
||||
return encoder.UInt8(uint8(v))
|
||||
case uint64:
|
||||
return encoder.UInt8(uint8(v))
|
||||
case int:
|
||||
return encoder.UInt8(uint8(v))
|
||||
|
||||
// this relies on Nullable never sending nil values through
|
||||
case *bool:
|
||||
return encoder.Bool(*v)
|
||||
case *uint8:
|
||||
return encoder.UInt8(*v)
|
||||
case *int64:
|
||||
return encoder.UInt8(uint8(*v))
|
||||
case *uint64:
|
||||
return encoder.UInt8(uint8(*v))
|
||||
case *int:
|
||||
return encoder.UInt8(uint8(*v))
|
||||
}
|
||||
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: u,
|
||||
}
|
||||
}
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
package column
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
UUIDLen = 16
|
||||
NullUUID = "00000000-0000-0000-0000-000000000000"
|
||||
)
|
||||
|
||||
var ErrInvalidUUIDFormat = errors.New("invalid UUID format")
|
||||
|
||||
type UUID struct {
|
||||
base
|
||||
scanType reflect.Type
|
||||
}
|
||||
|
||||
func (*UUID) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
|
||||
src, err := decoder.Fixed(UUIDLen)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
src = swap(src)
|
||||
|
||||
var uuid [36]byte
|
||||
{
|
||||
hex.Encode(uuid[:], src[:4])
|
||||
uuid[8] = '-'
|
||||
hex.Encode(uuid[9:13], src[4:6])
|
||||
uuid[13] = '-'
|
||||
hex.Encode(uuid[14:18], src[6:8])
|
||||
uuid[18] = '-'
|
||||
hex.Encode(uuid[19:23], src[8:10])
|
||||
uuid[23] = '-'
|
||||
hex.Encode(uuid[24:], src[10:])
|
||||
}
|
||||
return string(uuid[:]), nil
|
||||
}
|
||||
|
||||
func (u *UUID) Write(encoder *binary.Encoder, v interface{}) (err error) {
|
||||
var uuid []byte
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
if uuid, err = uuid2bytes(v); err != nil {
|
||||
return err
|
||||
}
|
||||
case []byte:
|
||||
if len(v) != UUIDLen {
|
||||
return fmt.Errorf("invalid raw UUID len '%s' (expected %d, got %d)", uuid, UUIDLen, len(uuid))
|
||||
}
|
||||
uuid = make([]byte, 16)
|
||||
copy(uuid, v)
|
||||
default:
|
||||
return &ErrUnexpectedType{
|
||||
T: v,
|
||||
Column: u,
|
||||
}
|
||||
}
|
||||
|
||||
uuid = swap(uuid)
|
||||
|
||||
if _, err := encoder.Write(uuid); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func swap(src []byte) []byte {
|
||||
_ = src[15]
|
||||
src[0], src[7] = src[7], src[0]
|
||||
src[1], src[6] = src[6], src[1]
|
||||
src[2], src[5] = src[5], src[2]
|
||||
src[3], src[4] = src[4], src[3]
|
||||
src[8], src[15] = src[15], src[8]
|
||||
src[9], src[14] = src[14], src[9]
|
||||
src[10], src[13] = src[13], src[10]
|
||||
src[11], src[12] = src[12], src[11]
|
||||
return src
|
||||
}
|
||||
|
||||
func uuid2bytes(str string) ([]byte, error) {
|
||||
var uuid [16]byte
|
||||
strLength := len(str)
|
||||
if strLength == 0 {
|
||||
str = NullUUID
|
||||
} else if strLength != 36 {
|
||||
return nil, ErrInvalidUUIDFormat
|
||||
}
|
||||
if str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-' {
|
||||
return nil, ErrInvalidUUIDFormat
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11, 14, 16,
|
||||
19, 21, 24, 26,
|
||||
28, 30, 32, 34,
|
||||
} {
|
||||
if v, ok := xtob(str[x], str[x+1]); !ok {
|
||||
return nil, ErrInvalidUUIDFormat
|
||||
} else {
|
||||
uuid[i] = v
|
||||
}
|
||||
}
|
||||
return uuid[:], nil
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts hex characters x1 and x2 into a byte.
|
||||
func xtob(x1, x2 byte) (byte, bool) {
|
||||
b1 := xvalues[x1]
|
||||
b2 := xvalues[x2]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
||||
-326
@@ -1,326 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/column"
|
||||
)
|
||||
|
||||
type offset [][]int
|
||||
|
||||
type Block struct {
|
||||
Values [][]interface{}
|
||||
Columns []column.Column
|
||||
NumRows uint64
|
||||
NumColumns uint64
|
||||
offsets []offset
|
||||
buffers []*buffer
|
||||
info blockInfo
|
||||
}
|
||||
|
||||
func (block *Block) Copy() *Block {
|
||||
return &Block{
|
||||
Columns: block.Columns,
|
||||
NumColumns: block.NumColumns,
|
||||
info: block.info,
|
||||
}
|
||||
}
|
||||
|
||||
func (block *Block) ColumnNames() []string {
|
||||
names := make([]string, 0, len(block.Columns))
|
||||
for _, column := range block.Columns {
|
||||
names = append(names, column.Name())
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func (block *Block) Read(serverInfo *ServerInfo, decoder *binary.Decoder) (err error) {
|
||||
if serverInfo.Revision > 0 {
|
||||
if err = block.info.read(decoder); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if block.NumColumns, err = decoder.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
if block.NumRows, err = decoder.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
block.Values = make([][]interface{}, block.NumColumns)
|
||||
if block.NumRows > 10 {
|
||||
for i := 0; i < int(block.NumColumns); i++ {
|
||||
block.Values[i] = make([]interface{}, 0, block.NumRows)
|
||||
}
|
||||
}
|
||||
for i := 0; i < int(block.NumColumns); i++ {
|
||||
var (
|
||||
value interface{}
|
||||
columnName string
|
||||
columnType string
|
||||
)
|
||||
if columnName, err = decoder.String(); err != nil {
|
||||
return err
|
||||
}
|
||||
if columnType, err = decoder.String(); err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := column.Factory(columnName, columnType, serverInfo.Timezone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
block.Columns = append(block.Columns, c)
|
||||
switch column := c.(type) {
|
||||
case *column.Array:
|
||||
if block.Values[i], err = column.ReadArray(decoder, int(block.NumRows)); err != nil {
|
||||
return err
|
||||
}
|
||||
case *column.Nullable:
|
||||
if block.Values[i], err = column.ReadNull(decoder, int(block.NumRows)); err != nil {
|
||||
return err
|
||||
}
|
||||
case *column.Tuple:
|
||||
if block.Values[i], err = column.ReadTuple(decoder, int(block.NumRows)); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
for row := 0; row < int(block.NumRows); row++ {
|
||||
if value, err = column.Read(decoder, false); err != nil {
|
||||
return err
|
||||
}
|
||||
block.Values[i] = append(block.Values[i], value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) writeArray(col column.Column, value Value, num, level int) error {
|
||||
if level > col.Depth() {
|
||||
arrColumn, ok := col.(*column.Array)
|
||||
if ok && strings.Contains(col.CHType(), "Nullable") {
|
||||
return arrColumn.WriteNull(block.buffers[num].Offset, block.buffers[num].Column, value.Interface())
|
||||
}
|
||||
return col.Write(block.buffers[num].Column, value.Interface())
|
||||
}
|
||||
|
||||
switch {
|
||||
case value.Kind() == reflect.Slice:
|
||||
if len(block.offsets[num]) < level {
|
||||
block.offsets[num] = append(block.offsets[num], []int{value.Len()})
|
||||
} else {
|
||||
block.offsets[num][level-1] = append(
|
||||
block.offsets[num][level-1],
|
||||
block.offsets[num][level-1][len(block.offsets[num][level-1])-1]+value.Len(),
|
||||
)
|
||||
}
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
if err := block.writeArray(col, value.Index(i), num, level+1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
if err := col.Write(block.buffers[num].Column, value.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) AppendRow(args []driver.Value) error {
|
||||
if len(block.Columns) != len(args) {
|
||||
return fmt.Errorf("block: expected %d arguments (columns: %s), got %d", len(block.Columns), strings.Join(block.ColumnNames(), ", "), len(args))
|
||||
}
|
||||
block.Reserve()
|
||||
{
|
||||
block.NumRows++
|
||||
}
|
||||
for num, c := range block.Columns {
|
||||
switch column := c.(type) {
|
||||
case *column.Array:
|
||||
if args[num] == nil {
|
||||
return fmt.Errorf("unsupported [nil] value is passed in argument %d, column is not Nullable", num)
|
||||
}
|
||||
value := reflect.ValueOf(args[num])
|
||||
if value.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("unsupported Array(T) type [%T]", value.Interface())
|
||||
}
|
||||
if err := block.writeArray(c, newValue(value), num, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
case *column.Nullable:
|
||||
if err := column.WriteNull(block.buffers[num].Offset, block.buffers[num].Column, args[num]); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := column.Write(block.buffers[num].Column, args[num]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) Reserve() {
|
||||
if len(block.buffers) == 0 {
|
||||
block.buffers = make([]*buffer, len(block.Columns))
|
||||
block.offsets = make([]offset, len(block.Columns))
|
||||
for i := 0; i < len(block.Columns); i++ {
|
||||
var (
|
||||
offsetBuffer = new(bytes.Buffer)
|
||||
columnBuffer = new(bytes.Buffer)
|
||||
)
|
||||
block.buffers[i] = &buffer{
|
||||
Offset: binary.NewEncoder(offsetBuffer),
|
||||
Column: binary.NewEncoder(columnBuffer),
|
||||
offsetBuffer: offsetBuffer,
|
||||
columnBuffer: columnBuffer,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (block *Block) Reset() {
|
||||
block.NumRows = 0
|
||||
block.NumColumns = 0
|
||||
block.Values = block.Values[:0]
|
||||
block.Columns = block.Columns[:0]
|
||||
block.info.reset()
|
||||
for _, buffer := range block.buffers {
|
||||
buffer.reset()
|
||||
}
|
||||
{
|
||||
block.offsets = nil
|
||||
block.buffers = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (block *Block) Write(serverInfo *ServerInfo, encoder *binary.Encoder) error {
|
||||
if serverInfo.Revision > 0 {
|
||||
if err := block.info.write(encoder); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := encoder.Uvarint(block.NumColumns); err != nil {
|
||||
return err
|
||||
}
|
||||
encoder.Uvarint(block.NumRows)
|
||||
defer func() {
|
||||
block.NumRows = 0
|
||||
for i := range block.offsets {
|
||||
block.offsets[i] = offset{}
|
||||
}
|
||||
}()
|
||||
for i, column := range block.Columns {
|
||||
encoder.String(column.Name())
|
||||
encoder.String(column.CHType())
|
||||
if len(block.buffers) == len(block.Columns) {
|
||||
for _, offsets := range block.offsets[i] {
|
||||
for _, offset := range offsets {
|
||||
if err := encoder.UInt64(uint64(offset)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := block.buffers[i].WriteTo(encoder); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type blockInfo struct {
|
||||
num1 uint64
|
||||
isOverflows bool
|
||||
num2 uint64
|
||||
bucketNum int32
|
||||
num3 uint64
|
||||
}
|
||||
|
||||
func (info *blockInfo) reset() {
|
||||
info.num1 = 0
|
||||
info.isOverflows = false
|
||||
info.num2 = 0
|
||||
info.bucketNum = 0
|
||||
info.num3 = 0
|
||||
}
|
||||
|
||||
func (info *blockInfo) read(decoder *binary.Decoder) error {
|
||||
var err error
|
||||
if info.num1, err = decoder.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.isOverflows, err = decoder.Bool(); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.num2, err = decoder.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.bucketNum, err = decoder.Int32(); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.num3, err = decoder.Uvarint(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (info *blockInfo) write(encoder *binary.Encoder) error {
|
||||
if err := encoder.Uvarint(1); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := encoder.Bool(info.isOverflows); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := encoder.Uvarint(2); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.bucketNum == 0 {
|
||||
info.bucketNum = -1
|
||||
}
|
||||
if err := encoder.Int32(info.bucketNum); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := encoder.Uvarint(0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type buffer struct {
|
||||
Offset *binary.Encoder
|
||||
Column *binary.Encoder
|
||||
offsetBuffer *bytes.Buffer
|
||||
columnBuffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (buf *buffer) WriteTo(w io.Writer) (int64, error) {
|
||||
var size int64
|
||||
{
|
||||
ln, err := buf.offsetBuffer.WriteTo(w)
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
size += ln
|
||||
}
|
||||
{
|
||||
ln, err := buf.columnBuffer.WriteTo(w)
|
||||
if err != nil {
|
||||
return size, err
|
||||
}
|
||||
size += ln
|
||||
}
|
||||
return size, nil
|
||||
}
|
||||
|
||||
func (buf *buffer) reset() {
|
||||
buf.offsetBuffer.Reset()
|
||||
buf.columnBuffer.Reset()
|
||||
}
|
||||
-277
@@ -1,277 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/column"
|
||||
"net"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
func (block *Block) WriteDate(c int, v time.Time) error {
|
||||
_, offset := v.Zone()
|
||||
nday := (v.Unix() + int64(offset)) / 24 / 3600
|
||||
return block.buffers[c].Column.UInt16(uint16(nday))
|
||||
}
|
||||
|
||||
func (block *Block) WriteDateNullable(c int, v *time.Time) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.UInt16(0)
|
||||
}
|
||||
return block.WriteDate(c, *v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteDateTime(c int, v time.Time) error {
|
||||
return block.buffers[c].Column.UInt32(uint32(v.Unix()))
|
||||
}
|
||||
|
||||
func (block *Block) WriteDateTimeNullable(c int, v *time.Time) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.UInt32(0)
|
||||
}
|
||||
return block.buffers[c].Column.UInt32(uint32(v.Unix()))
|
||||
}
|
||||
|
||||
func (block *Block) WriteBool(c int, v bool) error {
|
||||
if v {
|
||||
return block.buffers[c].Column.UInt8(1)
|
||||
}
|
||||
return block.buffers[c].Column.UInt8(0)
|
||||
}
|
||||
|
||||
func (block *Block) WriteBoolNullable(c int, v *bool) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil || !(*v) {
|
||||
return block.buffers[c].Column.UInt8(0)
|
||||
}
|
||||
return block.buffers[c].Column.UInt8(1)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt8(c int, v int8) error {
|
||||
return block.buffers[c].Column.Int8(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt8Nullable(c int, v *int8) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.Int8(0)
|
||||
}
|
||||
return block.buffers[c].Column.Int8(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt16(c int, v int16) error {
|
||||
return block.buffers[c].Column.Int16(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt16Nullable(c int, v *int16) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.Int16(0)
|
||||
}
|
||||
return block.buffers[c].Column.Int16(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt32(c int, v int32) error {
|
||||
return block.buffers[c].Column.Int32(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt32Nullable(c int, v *int32) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.Int32(0)
|
||||
}
|
||||
return block.buffers[c].Column.Int32(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt64(c int, v int64) error {
|
||||
return block.buffers[c].Column.Int64(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteInt64Nullable(c int, v *int64) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.Int64(0)
|
||||
}
|
||||
return block.buffers[c].Column.Int64(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt8(c int, v uint8) error {
|
||||
return block.buffers[c].Column.UInt8(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt8Nullable(c int, v *uint8) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.UInt8(0)
|
||||
}
|
||||
return block.buffers[c].Column.UInt8(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt16(c int, v uint16) error {
|
||||
return block.buffers[c].Column.UInt16(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt16Nullable(c int, v *uint16) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.UInt16(0)
|
||||
}
|
||||
return block.buffers[c].Column.UInt16(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt32(c int, v uint32) error {
|
||||
return block.buffers[c].Column.UInt32(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt32Nullable(c int, v *uint32) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.UInt32(0)
|
||||
}
|
||||
return block.buffers[c].Column.UInt32(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt64(c int, v uint64) error {
|
||||
return block.buffers[c].Column.UInt64(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteUInt64Nullable(c int, v *uint64) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.UInt64(0)
|
||||
}
|
||||
return block.buffers[c].Column.UInt64(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteFloat32(c int, v float32) error {
|
||||
return block.buffers[c].Column.Float32(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteFloat32Nullable(c int, v *float32) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.Float32(0)
|
||||
}
|
||||
return block.buffers[c].Column.Float32(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteFloat64(c int, v float64) error {
|
||||
return block.buffers[c].Column.Float64(v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteFloat64Nullable(c int, v *float64) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.buffers[c].Column.Float64(0)
|
||||
}
|
||||
return block.buffers[c].Column.Float64(*v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteBytes(c int, v []byte) error {
|
||||
if err := block.buffers[c].Column.Uvarint(uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := block.buffers[c].Column.Write(v); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) WriteBytesNullable(c int, v *[]byte) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.WriteBytes(c, []byte{})
|
||||
}
|
||||
return block.WriteBytes(c, *v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteString(c int, v string) error {
|
||||
if err := block.buffers[c].Column.Uvarint(uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := block.buffers[c].Column.Write(binary.Str2Bytes(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) WriteStringNullable(c int, v *string) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.WriteString(c, "")
|
||||
}
|
||||
return block.WriteString(c, *v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteFixedString(c int, v []byte) error {
|
||||
return block.Columns[c].Write(block.buffers[c].Column, v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteFixedStringNullable(c int, v *[]byte) error {
|
||||
writer := block.Columns[c].(*column.Nullable)
|
||||
return writer.WriteNull(block.buffers[c].Offset, block.buffers[c].Column, v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteIP(c int, v net.IP) error {
|
||||
return block.Columns[c].Write(block.buffers[c].Column, v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteIPNullable(c int, v net.IP) error {
|
||||
writer := block.Columns[c].(*column.Nullable)
|
||||
return writer.WriteNull(block.buffers[c].Offset, block.buffers[c].Column, v)
|
||||
}
|
||||
|
||||
func (block *Block) WriteArray(c int, v interface{}) error {
|
||||
return block.WriteArrayWithValue(c, newValue(reflect.ValueOf(v)))
|
||||
}
|
||||
|
||||
func (block *Block) WriteArrayWithValue(c int, value Value) error {
|
||||
if value.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("unsupported Array(T) type [%T]", value.Interface())
|
||||
}
|
||||
return block.writeArray(block.Columns[c], value, c, 1)
|
||||
}
|
||||
|
||||
func (block *Block) WriteArrayNullable(c int, v *interface{}) error {
|
||||
if err := block.buffers[c].Offset.Bool(v == nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
return block.Columns[c].Write(block.buffers[c].Column, []string{})
|
||||
}
|
||||
return block.WriteArray(c, *v)
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
)
|
||||
|
||||
const ClientName = "Golang SQLDriver"
|
||||
|
||||
const (
|
||||
ClickHouseRevision = 54213
|
||||
ClickHouseDBMSVersionMajor = 1
|
||||
ClickHouseDBMSVersionMinor = 1
|
||||
)
|
||||
|
||||
type ClientInfo struct{}
|
||||
|
||||
func (ClientInfo) Write(encoder *binary.Encoder) error {
|
||||
encoder.String(ClientName)
|
||||
encoder.Uvarint(ClickHouseDBMSVersionMajor)
|
||||
encoder.Uvarint(ClickHouseDBMSVersionMinor)
|
||||
encoder.Uvarint(ClickHouseRevision)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ClientInfo) String() string {
|
||||
return fmt.Sprintf("%s %d.%d.%d", ClientName, ClickHouseDBMSVersionMajor, ClickHouseDBMSVersionMinor, ClickHouseRevision)
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
//"io"
|
||||
"time"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/lib/binary"
|
||||
"github.com/ClickHouse/clickhouse-go/lib/protocol"
|
||||
)
|
||||
|
||||
type ServerInfo struct {
|
||||
Name string
|
||||
Revision uint64
|
||||
MinorVersion uint64
|
||||
MajorVersion uint64
|
||||
Timezone *time.Location
|
||||
}
|
||||
|
||||
func (srv *ServerInfo) Read(decoder *binary.Decoder) (err error) {
|
||||
if srv.Name, err = decoder.String(); err != nil {
|
||||
return fmt.Errorf("could not read server name: %v", err)
|
||||
}
|
||||
if srv.MajorVersion, err = decoder.Uvarint(); err != nil {
|
||||
return fmt.Errorf("could not read server major version: %v", err)
|
||||
}
|
||||
if srv.MinorVersion, err = decoder.Uvarint(); err != nil {
|
||||
return fmt.Errorf("could not read server minor version: %v", err)
|
||||
}
|
||||
if srv.Revision, err = decoder.Uvarint(); err != nil {
|
||||
return fmt.Errorf("could not read server revision: %v", err)
|
||||
}
|
||||
if srv.Revision >= protocol.DBMS_MIN_REVISION_WITH_SERVER_TIMEZONE {
|
||||
timezone, err := decoder.String()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read server timezone: %v", err)
|
||||
}
|
||||
if srv.Timezone, err = time.LoadLocation(timezone); err != nil {
|
||||
return fmt.Errorf("could not load time location: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv ServerInfo) String() string {
|
||||
return fmt.Sprintf("%s %d.%d.%d (%s)", srv.Name, srv.MajorVersion, srv.MinorVersion, srv.Revision, srv.Timezone)
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package data
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Value is a writable value.
|
||||
type Value interface {
|
||||
// Kind returns value's Kind.
|
||||
Kind() reflect.Kind
|
||||
|
||||
// Len returns value's length.
|
||||
// It panics if value's Kind is not Array, Chan, Map, Slice, or String.
|
||||
Len() int
|
||||
|
||||
// Index returns value's i'th element.
|
||||
// It panics if value's Kind is not Array, Slice, or String or i is out of range.
|
||||
Index(i int) Value
|
||||
|
||||
// Interface returns value's current value as an interface{}.
|
||||
Interface() interface{}
|
||||
}
|
||||
|
||||
// value is a wrapper that wraps reflect.Value to comply with Value interface.
|
||||
type value struct {
|
||||
reflect.Value
|
||||
}
|
||||
|
||||
func newValue(v reflect.Value) Value {
|
||||
return value{Value: v}
|
||||
}
|
||||
|
||||
func (v value) Index(i int) Value {
|
||||
return newValue(v.Value.Index(i))
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
Copyright 2011-2012 Branimir Karadzic. All rights reserved.
|
||||
Copyright 2013 Damian Gryski. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
// Copyright 2011-2012 Branimir Karadzic. All rights reserved.
|
||||
// Copyright 2013 Damian Gryski. All rights reserved.
|
||||
|
||||
// @LINK: https://github.com/bkaradzic/go-lz4
|
||||
// @NOTE: The code is modified to be high performance and less memory usage
|
||||
|
||||
package lz4
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// +build gofuzz
|
||||
|
||||
package lz4
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
func Fuzz(data []byte) int {
|
||||
|
||||
if len(data) < 4 {
|
||||
return 0
|
||||
}
|
||||
|
||||
ln := binary.LittleEndian.Uint32(data)
|
||||
if ln > (1 << 21) {
|
||||
return 0
|
||||
}
|
||||
|
||||
if _, err := Decode(nil, data); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
-179
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2012 Branimir Karadzic. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package lz4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrCorrupt indicates the input was corrupt
|
||||
ErrCorrupt = errors.New("corrupt input")
|
||||
)
|
||||
|
||||
const (
|
||||
mlBits = 4
|
||||
mlMask = (1 << mlBits) - 1
|
||||
runBits = 8 - mlBits
|
||||
runMask = (1 << runBits) - 1
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
src []byte
|
||||
dst []byte
|
||||
spos uint32
|
||||
dpos uint32
|
||||
ref uint32
|
||||
}
|
||||
|
||||
func (d *decoder) readByte() (uint8, error) {
|
||||
if int(d.spos) == len(d.src) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
b := d.src[d.spos]
|
||||
d.spos++
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (d *decoder) getLen() (uint32, error) {
|
||||
|
||||
length := uint32(0)
|
||||
ln, err := d.readByte()
|
||||
if err != nil {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
for ln == 255 {
|
||||
length += 255
|
||||
ln, err = d.readByte()
|
||||
if err != nil {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
}
|
||||
length += uint32(ln)
|
||||
|
||||
return length, nil
|
||||
}
|
||||
|
||||
func (d *decoder) cp(length, decr uint32) {
|
||||
|
||||
if int(d.ref+length) < int(d.dpos) {
|
||||
copy(d.dst[d.dpos:], d.dst[d.ref:d.ref+length])
|
||||
} else {
|
||||
for ii := uint32(0); ii < length; ii++ {
|
||||
d.dst[d.dpos+ii] = d.dst[d.ref+ii]
|
||||
}
|
||||
}
|
||||
d.dpos += length
|
||||
d.ref += length - decr
|
||||
}
|
||||
|
||||
func (d *decoder) finish(err error) error {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode returns the decoded form of src. The returned slice may be a
|
||||
// subslice of dst if it was large enough to hold the entire decoded block.
|
||||
func Decode(dst, src []byte) (int, error) {
|
||||
d := decoder{src: src, dst: dst, spos: 0}
|
||||
|
||||
decr := []uint32{0, 3, 2, 3}
|
||||
|
||||
for {
|
||||
code, err := d.readByte()
|
||||
if err != nil {
|
||||
return len(d.dst), d.finish(err)
|
||||
}
|
||||
|
||||
length := uint32(code >> mlBits)
|
||||
if length == runMask {
|
||||
ln, err := d.getLen()
|
||||
if err != nil {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
length += ln
|
||||
}
|
||||
|
||||
if int(d.spos+length) > len(d.src) || int(d.dpos+length) > len(d.dst) {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
|
||||
for ii := uint32(0); ii < length; ii++ {
|
||||
d.dst[d.dpos+ii] = d.src[d.spos+ii]
|
||||
}
|
||||
|
||||
d.spos += length
|
||||
d.dpos += length
|
||||
|
||||
if int(d.spos) == len(d.src) {
|
||||
return len(d.dst), nil
|
||||
}
|
||||
|
||||
if int(d.spos+2) >= len(d.src) {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
|
||||
back := uint32(d.src[d.spos]) | uint32(d.src[d.spos+1])<<8
|
||||
|
||||
if back > d.dpos {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
|
||||
d.spos += 2
|
||||
d.ref = d.dpos - back
|
||||
|
||||
length = uint32(code & mlMask)
|
||||
if length == mlMask {
|
||||
ln, err := d.getLen()
|
||||
if err != nil {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
length += ln
|
||||
}
|
||||
|
||||
literal := d.dpos - d.ref
|
||||
|
||||
if literal < 4 {
|
||||
if int(d.dpos+4) > len(d.dst) {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
|
||||
d.cp(4, decr[literal])
|
||||
} else {
|
||||
length += 4
|
||||
}
|
||||
|
||||
if int(d.dpos+length) > len(d.dst) {
|
||||
return 0, ErrCorrupt
|
||||
}
|
||||
|
||||
d.cp(length, 0)
|
||||
}
|
||||
}
|
||||
-203
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2012 Branimir Karadzic. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package lz4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
minMatch = 4
|
||||
hashLog = 16
|
||||
hashTableSize = 1 << hashLog
|
||||
hashShift = (minMatch * 8) - hashLog
|
||||
incompressible uint32 = 128
|
||||
uninitHash = 0x88888888
|
||||
|
||||
mfLimit = 8 + minMatch // The last match cannot start within the last 12 bytes.
|
||||
// MaxInputSize is the largest buffer than can be compressed in a single block
|
||||
MaxInputSize = 0x7E000000
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTooLarge indicates the input buffer was too large
|
||||
ErrTooLarge = errors.New("input too large")
|
||||
ErrEncodeTooSmall = errors.New("encode buffer too small")
|
||||
|
||||
hashPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]uint32, hashTableSize)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type encoder struct {
|
||||
src []byte
|
||||
dst []byte
|
||||
hashTable []uint32
|
||||
pos uint32
|
||||
anchor uint32
|
||||
dpos uint32
|
||||
}
|
||||
|
||||
// CompressBound returns the maximum length of a lz4 block
|
||||
func CompressBound(isize int) int {
|
||||
if isize > MaxInputSize {
|
||||
return 0
|
||||
}
|
||||
return isize + ((isize) / 255) + 16
|
||||
}
|
||||
|
||||
func (e *encoder) writeLiterals(length, mlLen, pos uint32) {
|
||||
|
||||
ln := length
|
||||
|
||||
var code byte
|
||||
if ln > runMask-1 {
|
||||
code = runMask
|
||||
} else {
|
||||
code = byte(ln)
|
||||
}
|
||||
|
||||
if mlLen > mlMask-1 {
|
||||
e.dst[e.dpos] = (code << mlBits) + byte(mlMask)
|
||||
} else {
|
||||
e.dst[e.dpos] = (code << mlBits) + byte(mlLen)
|
||||
}
|
||||
e.dpos++
|
||||
|
||||
if code == runMask {
|
||||
ln -= runMask
|
||||
for ; ln > 254; ln -= 255 {
|
||||
e.dst[e.dpos] = 255
|
||||
e.dpos++
|
||||
}
|
||||
|
||||
e.dst[e.dpos] = byte(ln)
|
||||
e.dpos++
|
||||
}
|
||||
|
||||
for ii := uint32(0); ii < length; ii++ {
|
||||
e.dst[e.dpos+ii] = e.src[pos+ii]
|
||||
}
|
||||
|
||||
e.dpos += length
|
||||
}
|
||||
|
||||
// Encode returns the encoded form of src. The returned array may be a
|
||||
// sub-slice of dst if it was large enough to hold the entire output.
|
||||
func Encode(dst, src []byte) (compressedSize int, error error) {
|
||||
if len(src) >= MaxInputSize {
|
||||
return 0, ErrTooLarge
|
||||
}
|
||||
|
||||
if n := CompressBound(len(src)); len(dst) < n {
|
||||
return 0, ErrEncodeTooSmall
|
||||
}
|
||||
|
||||
hashTable := hashPool.Get().([]uint32)
|
||||
for i := range hashTable {
|
||||
hashTable[i] = 0
|
||||
}
|
||||
e := encoder{src: src, dst: dst, hashTable: hashTable}
|
||||
defer func() {
|
||||
hashPool.Put(hashTable)
|
||||
}()
|
||||
// binary.LittleEndian.PutUint32(dst, uint32(len(src)))
|
||||
// e.dpos = 0
|
||||
|
||||
var (
|
||||
step uint32 = 1
|
||||
limit = incompressible
|
||||
)
|
||||
|
||||
for {
|
||||
if int(e.pos)+12 >= len(e.src) {
|
||||
e.writeLiterals(uint32(len(e.src))-e.anchor, 0, e.anchor)
|
||||
return int(e.dpos), nil
|
||||
}
|
||||
|
||||
sequence := uint32(e.src[e.pos+3])<<24 | uint32(e.src[e.pos+2])<<16 | uint32(e.src[e.pos+1])<<8 | uint32(e.src[e.pos+0])
|
||||
|
||||
hash := (sequence * 2654435761) >> hashShift
|
||||
ref := e.hashTable[hash] + uninitHash
|
||||
e.hashTable[hash] = e.pos - uninitHash
|
||||
|
||||
if ((e.pos-ref)>>16) != 0 || uint32(e.src[ref+3])<<24|uint32(e.src[ref+2])<<16|uint32(e.src[ref+1])<<8|uint32(e.src[ref+0]) != sequence {
|
||||
if e.pos-e.anchor > limit {
|
||||
limit <<= 1
|
||||
step += 1 + (step >> 2)
|
||||
}
|
||||
e.pos += step
|
||||
continue
|
||||
}
|
||||
|
||||
if step > 1 {
|
||||
e.hashTable[hash] = ref - uninitHash
|
||||
e.pos -= step - 1
|
||||
step = 1
|
||||
continue
|
||||
}
|
||||
limit = incompressible
|
||||
|
||||
ln := e.pos - e.anchor
|
||||
back := e.pos - ref
|
||||
|
||||
anchor := e.anchor
|
||||
|
||||
e.pos += minMatch
|
||||
ref += minMatch
|
||||
e.anchor = e.pos
|
||||
|
||||
for int(e.pos) < len(e.src)-5 && e.src[e.pos] == e.src[ref] {
|
||||
e.pos++
|
||||
ref++
|
||||
}
|
||||
|
||||
mlLen := e.pos - e.anchor
|
||||
|
||||
e.writeLiterals(ln, mlLen, anchor)
|
||||
e.dst[e.dpos] = uint8(back)
|
||||
e.dst[e.dpos+1] = uint8(back >> 8)
|
||||
e.dpos += 2
|
||||
|
||||
if mlLen > mlMask-1 {
|
||||
mlLen -= mlMask
|
||||
for mlLen > 254 {
|
||||
mlLen -= 255
|
||||
|
||||
e.dst[e.dpos] = 255
|
||||
e.dpos++
|
||||
}
|
||||
|
||||
e.dst[e.dpos] = byte(mlLen)
|
||||
e.dpos++
|
||||
}
|
||||
|
||||
e.anchor = e.pos
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
# ClickHouse Native protocol
|
||||
|
||||
# Handshake
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package protocol
|
||||
|
||||
const (
|
||||
DBMS_MIN_REVISION_WITH_SERVER_TIMEZONE = 54058
|
||||
DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO = 54060
|
||||
)
|
||||
|
||||
const (
|
||||
ClientHello = 0
|
||||
ClientQuery = 1
|
||||
ClientData = 2
|
||||
ClientCancel = 3
|
||||
ClientPing = 4
|
||||
)
|
||||
|
||||
const (
|
||||
CompressEnable uint64 = 1
|
||||
CompressDisable uint64 = 0
|
||||
)
|
||||
|
||||
const (
|
||||
StateComplete = 2
|
||||
)
|
||||
|
||||
const (
|
||||
ServerHello = 0
|
||||
ServerData = 1
|
||||
ServerException = 2
|
||||
ServerProgress = 3
|
||||
ServerPong = 4
|
||||
ServerEndOfStream = 5
|
||||
ServerProfileInfo = 6
|
||||
ServerTotals = 7
|
||||
ServerExtremes = 8
|
||||
)
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
// Timezoneless date/datetime types
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Truncate timezone
|
||||
//
|
||||
// clickhouse.Date(time.Date(2017, 1, 1, 0, 0, 0, 0, time.Local)) -> time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
type Date time.Time
|
||||
|
||||
func (date Date) Value() (driver.Value, error) {
|
||||
return date.convert(), nil
|
||||
}
|
||||
|
||||
func (date Date) convert() time.Time {
|
||||
return time.Date(time.Time(date).Year(), time.Time(date).Month(), time.Time(date).Day(), 0, 0, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
// Truncate timezone
|
||||
//
|
||||
// clickhouse.DateTime(time.Date(2017, 1, 1, 0, 0, 0, 0, time.Local)) -> time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
type DateTime time.Time
|
||||
|
||||
func (datetime DateTime) Value() (driver.Value, error) {
|
||||
return datetime.convert(), nil
|
||||
}
|
||||
|
||||
func (datetime DateTime) convert() time.Time {
|
||||
return time.Date(
|
||||
time.Time(datetime).Year(),
|
||||
time.Time(datetime).Month(),
|
||||
time.Time(datetime).Day(),
|
||||
time.Time(datetime).Hour(),
|
||||
time.Time(datetime).Minute(),
|
||||
time.Time(datetime).Second(),
|
||||
1,
|
||||
time.UTC,
|
||||
)
|
||||
}
|
||||
|
||||
var (
|
||||
_ driver.Valuer = Date{}
|
||||
_ driver.Valuer = DateTime{}
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user