[9.5.x] Backport release prs (#89571)
* Chore: Add go workspace (#83191) --------- Co-authored-by: ismail simsek <ismailsimsek09@gmail.com> * CI: Make pkg/build its own module, remove unused Grafana modules in go.mo… (#89243) * Make pkg/build its own module, remove unused Grafana modules in go.mod/go.sum * fix go.work format * log errors on file close errors * CI: Add release-pr workflow (#89005) * Add release-pr workflow * update CODEOWNERS * CI: Trigger release pr workflow when a release is completed (#89062) * Automation: Verify release artifacts on grafana.com (#89197) * baldm0mma/verify_release/ create verify_release_for_download function * baldm0mma/verify_release/ add name, image, env * baldm0mma/verify_release/ add initial commands * baldm0mma/verify_release/ add deps? * baldm0mma/verify_release/ update location * baldm0mma/verify_release/ add anno to lib-star * bald0mma/verify_release/ update func name to verify_grafanacom_step * baldm0mma/verify_release/ add verify shell script * baldm0mma/verify_release/ add script content, first attempt * baldm0mma/verify_release/ add node image to verify_grafanacom_step * baldm0mma/verify_release/ add gcom secret note * baldm0mma/verify_release/ add sudo to apt-get * baldm0mma/verify_release/ add anno * baldm0mma/verify_release/ add anno to secrets * baldm0mma/verify_release/ update commands to reflect node env image * baldm0mma/verify_release/ update annos * baldm0mma/verify_release/ update tag variable * baldm0mma/verify release/ add whitespace * baldm0mma/verify_releases/ update with no bash loops * baldm0mma/verify_release/ update exit logic * baldm0mma/verify_release/ remove annos * baldm0mma/verify_releasse/ resign and build yml * baldm0mma/verify_release/ remove annos * baldm0mma/verify_release/ update signature * baldm0mma/verify_release/ download curl * baldm0mma/verify_release/ remove temp key folder removal * baldm0mma/verify_release/ account for artifact download time * baldm0mma/verify_release/ add anno * baldm0mma/verify_release/ update location * baldm0mma/verify_release/ update script * baldm0mma/verify_release/ make drone * baldm0mma/verify_release/ update script for oss or ent * baldm0mma/verify_release/ add promotion option * baldm0mma/verify_release/ make drone * Update scripts/drone/events/release.star Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * Update scripts/drone/steps/lib.star Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * Update scripts/drone/steps/lib.star Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * baldm0mma/verify_release/ update drone * Update scripts/drone/events/release.star Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * baldm0mma/verify_release/ update drone * Update scripts/drone/steps/lib.star Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * baldm0mma/update drone * baldm0mma/verify_release/ update path * baldm0mma/verify_release/ make drone * baldm0mma/update drone * Apply suggestions from code review Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * baldm0mma/verify_release/ update for loop to account for failure * baldm0mma/verify_release/ make drone * baldm0mma/verify_release/ make format-drone * baldm0mma/verify_release/ rem unused var --------- Co-authored-by: Kevin Minehart <5140827+kminehart@users.noreply.github.com> * CI: Add bump-version action to the release PR workflow (#89491) * Remove pkg/build/actions * remove pkg/util/xorm since it's not being used anyways... * allow grpc.dial --------- Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com> Co-authored-by: ismail simsek <ismailsimsek09@gmail.com> Co-authored-by: Jev Forsberg <46619047+baldm0mma@users.noreply.github.com>
This commit is contained in:
co-authored by
ismail simsek
Todd Treece
Jev Forsberg
parent
1ba5cd9853
commit
a453a065be
@@ -6,9 +6,8 @@ import (
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
)
|
||||
|
||||
// VerifyStorybook Action implements the sub-command "verify-storybook".
|
||||
@@ -19,7 +18,7 @@ func VerifyStorybook(c *cli.Context) error {
|
||||
"packages/grafana-ui/dist/storybook/index.html",
|
||||
"packages/grafana-ui/dist/storybook/iframe.html"}
|
||||
for _, p := range paths {
|
||||
exists, err := fs.Exists(filepath.Join(grafanaDir, p))
|
||||
exists, err := fsutil.Exists(filepath.Join(grafanaDir, p))
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to verify Storybook build: %s", err), 1)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// CopyRecursive copies files and directories recursively.
|
||||
func CopyRecursive(src, dst string) error {
|
||||
sfi, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !sfi.IsDir() {
|
||||
return CopyFile(src, dst)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dst); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(dst, sfi.Mode()); err != nil {
|
||||
return fmt.Errorf("failed to create directory %q: %s", dst, err)
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
srcFi, err := os.Stat(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch srcFi.Mode() & os.ModeType {
|
||||
case os.ModeDir:
|
||||
if err := CopyRecursive(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
case os.ModeSymlink:
|
||||
link, err := os.Readlink(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Symlink(link, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := CopyFile(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if srcFi.Mode()&os.ModeSymlink != 0 {
|
||||
if err := os.Chmod(dstPath, srcFi.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
module github.com/grafana/grafana/pkg/build
|
||||
|
||||
go 1.21.10
|
||||
|
||||
// Override docker/docker to avoid:
|
||||
// go: github.com/drone-runners/drone-runner-docker@v1.8.2 requires
|
||||
// github.com/docker/docker@v0.0.0-00010101000000-000000000000: invalid version: unknown revision 000000000000
|
||||
replace github.com/docker/docker => github.com/moby/moby v23.0.4+incompatible
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.38.0 // @grafana/grafana-backend-group
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // @grafana/grafana-release-guild
|
||||
github.com/aws/aws-sdk-go v1.51.31 // @grafana/aws-datasources
|
||||
github.com/blang/semver/v4 v4.0.0 // @grafana/grafana-release-guild
|
||||
github.com/docker/docker v26.0.1+incompatible // @grafana/grafana-release-guild
|
||||
github.com/drone/drone-cli v1.6.1 // @grafana/grafana-release-guild
|
||||
github.com/gogo/protobuf v1.3.2 // indirect; @grafana/alerting-backend
|
||||
github.com/golang/protobuf v1.5.4 // indirect; @grafana/grafana-backend-group
|
||||
github.com/google/go-cmp v0.6.0 // @grafana/grafana-backend-group
|
||||
github.com/google/go-github v17.0.0+incompatible // @grafana/grafana-release-guild
|
||||
github.com/google/go-github/v45 v45.2.0 // @grafana/grafana-release-guild
|
||||
github.com/google/uuid v1.6.0 // indirect; @grafana/grafana-backend-group
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 // indirect; @grafana/grafana-backend-group
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect; @grafana/grafana-backend-group
|
||||
github.com/stretchr/testify v1.9.0 // @grafana/grafana-backend-group
|
||||
github.com/urfave/cli v1.22.15 // @grafana/grafana-backend-group
|
||||
github.com/urfave/cli/v2 v2.25.1 // @grafana/grafana-backend-group
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 // indirect; @grafana/plugins-platform-backend
|
||||
go.opentelemetry.io/otel v1.26.0 // indirect; @grafana/grafana-backend-group
|
||||
go.opentelemetry.io/otel/sdk v1.26.0 // indirect; @grafana/grafana-backend-group
|
||||
go.opentelemetry.io/otel/trace v1.26.0 // indirect; @grafana/grafana-backend-group
|
||||
golang.org/x/crypto v0.24.0 // indirect; @grafana/grafana-backend-group
|
||||
golang.org/x/mod v0.18.0 // @grafana/grafana-backend-group
|
||||
golang.org/x/net v0.26.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources
|
||||
golang.org/x/oauth2 v0.20.0 // @grafana/identity-access-team
|
||||
golang.org/x/sync v0.7.0 // indirect; @grafana/alerting-backend
|
||||
golang.org/x/text v0.16.0 // indirect; @grafana/grafana-backend-group
|
||||
golang.org/x/time v0.5.0 // indirect; @grafana/grafana-backend-group
|
||||
golang.org/x/tools v0.22.0 // indirect; @grafana/grafana-as-code
|
||||
google.golang.org/api v0.176.0 // @grafana/grafana-backend-group
|
||||
google.golang.org/grpc v1.64.0 // indirect; @grafana/plugins-platform-backend
|
||||
google.golang.org/protobuf v1.34.1 // indirect; @grafana/plugins-platform-backend
|
||||
gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.112.1 // indirect
|
||||
cloud.google.com/go/auth v0.2.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
||||
cloud.google.com/go/iam v1.1.6 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/bmatcuk/doublestar v1.1.1 // indirect
|
||||
github.com/buildkite/yaml v2.1.0+incompatible // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2 // indirect
|
||||
github.com/drone/drone-go v1.7.1 // indirect
|
||||
github.com/drone/envsubst v1.0.3 // indirect
|
||||
github.com/drone/runner-go v1.12.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect; @grafana/grafana-app-platform-squad
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220512140940-7b36cea86235 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.26.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect; @grafana/grafana-backend-group
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gotest.tools/v3 v3.5.1 // indirect
|
||||
)
|
||||
|
||||
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
@@ -0,0 +1,342 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
|
||||
cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
|
||||
cloud.google.com/go/auth v0.2.2 h1:gmxNJs4YZYcw6YvKRtVBaF2fyUE6UrWPyzU8jHvYfmI=
|
||||
cloud.google.com/go/auth v0.2.2/go.mod h1:2bDNJWtWziDT3Pu1URxHHbkHE/BbOCuyUiKIGcNvafo=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.1 h1:VSPmMmUlT8CkIZ2PzD9AlLN+R3+D1clXMWHHa6vG/Ag=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.1/go.mod h1:tOdK/k+D2e4GEwfBRA48dKNQiDsqIXxLh7VU319eV0g=
|
||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc=
|
||||
cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
|
||||
cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg=
|
||||
cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY=
|
||||
github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d/go.mod h1:3cARGAK9CfW3HoxCy1a0G4TKrdiKke8ftOMEOHyySYs=
|
||||
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/aws/aws-sdk-go v1.51.31 h1:4TM+sNc+Dzs7wY1sJ0+J8i60c6rkgnKP1pvPx8ghsSY=
|
||||
github.com/aws/aws-sdk-go v1.51.31/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/buildkite/yaml v2.1.0+incompatible h1:xirI+ql5GzfikVNDmt+yeiXpf/v1Gt03qXTtT5WXdr8=
|
||||
github.com/buildkite/yaml v2.1.0+incompatible/go.mod h1:UoU8vbcwu1+vjZq01+KrpSeLBgQQIjL/H7Y6KwikUrI=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2 h1:F7+39FSyzEUqLXYMvTdTGBhCS79ODDIhw3DQeF5GYT8=
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2/go.mod h1:JR3pZeVZKKpkbTajiq0YtAx9WutkODdVKZGNR83kEwE=
|
||||
github.com/drone/drone-cli v1.6.1 h1:Beh0opEGR5XYezOyOmiqWzTMBGHkGDrh2tIG1cY/5GY=
|
||||
github.com/drone/drone-cli v1.6.1/go.mod h1://HC780Gua3Nhob/I2VPL3nTqmleEE/HIhGhTcJb2ds=
|
||||
github.com/drone/drone-go v1.7.1 h1:ZX+3Rs8YHUSUQ5mkuMLmm1zr1ttiiE2YGNxF3AnyDKw=
|
||||
github.com/drone/drone-go v1.7.1/go.mod h1:fxCf9jAnXDZV1yDr0ckTuWd1intvcQwfJmTRpTZ1mXg=
|
||||
github.com/drone/envsubst v1.0.2/go.mod h1:bkZbnc/2vh1M12Ecn7EYScpI4YGYU0etwLJICOWi8Z0=
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/drone/runner-go v1.12.0 h1:zUjDj9ylsJ4n4Mvy4znddq/Z4EBzcUXzTltpzokKtgs=
|
||||
github.com/drone/runner-go v1.12.0/go.mod h1:vu4pPPYDoeN6vdYQAY01GGGsAIW4aLganJNaa8Fx8zE=
|
||||
github.com/drone/signal v1.0.0/go.mod h1:S8t92eFT0g4WUgEc/LxG+LCuiskpMNsG0ajAMGnyZpc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/gogo/protobuf v0.0.0-20170307180453-100ba4e88506/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI=
|
||||
github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
|
||||
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/moby/moby v23.0.4+incompatible h1:A/pe8vi9KIKhNbzR0G3wW4ACKDsMgXILBveMqiJNa8M=
|
||||
github.com/moby/moby v23.0.4+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/natessilva/dag v0.0.0-20180124060714-7194b8dcc5c4/go.mod h1:cojhOHk1gbMeklOyDP2oKKLftefXoJreOQGOrXk+Z38=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220512140940-7b36cea86235 h1:DxS3bbeUSCpMQr3mTez5PIDrS+yBeBsoDsftOhqB1Fg=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220512140940-7b36cea86235/go.mod h1:K/JAU0m27RFhDRX4PcFdIKntROP6y5Ed6O91aZYDQfs=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM=
|
||||
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
|
||||
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
|
||||
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
|
||||
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
|
||||
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
|
||||
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
|
||||
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
|
||||
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
|
||||
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
|
||||
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
|
||||
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
|
||||
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/api v0.176.0 h1:dHj1/yv5Dm/eQTXiP9hNCRT3xzJHWXeNdRq29XbMxoE=
|
||||
google.golang.org/api v0.176.0/go.mod h1:Rra+ltKu14pps/4xTycZfobMgLpbosoaaL7c+SEMrO8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
)
|
||||
|
||||
// writeRpmMacros writes ~/.rpmmacros.
|
||||
@@ -31,7 +31,7 @@ func writeRpmMacros(homeDir, gpgPassPath string) error {
|
||||
// Import imports the GPG package signing key.
|
||||
// ~/.rpmmacros also gets written.
|
||||
func Import(cfg config.Config) error {
|
||||
exists, err := fs.Exists(cfg.GPGPrivateKey)
|
||||
exists, err := fsutil.Exists(cfg.GPGPrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
"github.com/grafana/grafana/pkg/build/grafana"
|
||||
"github.com/grafana/grafana/pkg/build/plugins"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -99,7 +99,7 @@ func packageGrafana(
|
||||
p syncutil.WorkerPool,
|
||||
) error {
|
||||
distDir := filepath.Join(grafanaDir, "dist")
|
||||
exists, err := fs.Exists(distDir)
|
||||
exists, err := fsutil.Exists(distDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -317,28 +317,28 @@ func createPackage(srcDir string, options linuxPackageOptions) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := fs.CopyFile(filepath.Join(options.wrapperFilePath, binary),
|
||||
if err := fsutil.CopyFile(filepath.Join(options.wrapperFilePath, binary),
|
||||
filepath.Join(packageRoot, "usr", "sbin", binary)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fs.CopyFile(filepath.Join(options.wrapperFilePath, cliBinary),
|
||||
if err := fsutil.CopyFile(filepath.Join(options.wrapperFilePath, cliBinary),
|
||||
filepath.Join(packageRoot, "usr", "sbin", cliBinary)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fs.CopyFile(filepath.Join(options.wrapperFilePath, serverBinary),
|
||||
if err := fsutil.CopyFile(filepath.Join(options.wrapperFilePath, serverBinary),
|
||||
filepath.Join(packageRoot, "usr", "sbin", serverBinary)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fs.CopyFile(options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath)); err != nil {
|
||||
if err := fsutil.CopyFile(options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fs.CopyFile(options.defaultFileSrc, filepath.Join(packageRoot, options.etcDefaultFilePath)); err != nil {
|
||||
if err := fsutil.CopyFile(options.defaultFileSrc, filepath.Join(packageRoot, options.etcDefaultFilePath)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fs.CopyFile(options.systemdFileSrc, filepath.Join(packageRoot, options.systemdServiceFilePath)); err != nil {
|
||||
if err := fsutil.CopyFile(options.systemdFileSrc, filepath.Join(packageRoot, options.systemdServiceFilePath)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fs.CopyRecursive(srcDir, filepath.Join(packageRoot, options.homeDir)); err != nil {
|
||||
if err := fsutil.CopyRecursive(srcDir, filepath.Join(packageRoot, options.homeDir)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ func executeFPM(options linuxPackageOptions, packageRoot, srcDir string) error {
|
||||
}
|
||||
log.Printf("Creating %s package: %s...", options.packageType, cmdStr)
|
||||
const rvmPath = "/etc/profile.d/rvm.sh"
|
||||
exists, err := fs.Exists(rvmPath)
|
||||
exists, err := fsutil.Exists(rvmPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -439,7 +439,7 @@ func copyPubDir(grafanaDir, tmpDir string) error {
|
||||
srcPubDir := filepath.Join(grafanaDir, "public")
|
||||
tgtPubDir := filepath.Join(tmpDir, "public")
|
||||
log.Printf("Copying %q to %q...", srcPubDir, tgtPubDir)
|
||||
if err := fs.CopyRecursive(srcPubDir, tgtPubDir); err != nil {
|
||||
if err := fsutil.CopyRecursive(srcPubDir, tgtPubDir); err != nil {
|
||||
return fmt.Errorf("failed to copy %q to %q: %w", srcPubDir, tgtPubDir, err)
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ func copyBinaries(grafanaDir, tmpDir string, args grafana.BuildArgs, edition con
|
||||
srcPath := filepath.Join(binDir, file.Name())
|
||||
tgtPath := filepath.Join(tgtDir, file.Name())
|
||||
|
||||
if err := fs.CopyFile(srcPath, tgtPath); err != nil {
|
||||
if err := fsutil.CopyFile(srcPath, tgtPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -491,7 +491,7 @@ func copyConfFiles(grafanaDir, tmpDir string) error {
|
||||
}
|
||||
for _, info := range infos {
|
||||
fpath := filepath.Join(confDir, info.Name())
|
||||
if err := fs.CopyRecursive(fpath, filepath.Join(tmpDir, "conf", info.Name())); err != nil {
|
||||
if err := fsutil.CopyRecursive(fpath, filepath.Join(tmpDir, "conf", info.Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -510,7 +510,7 @@ func copyPlugins(ctx context.Context, v config.Variant, grafanaDir, tmpDir strin
|
||||
}
|
||||
|
||||
tgtDir := filepath.Join(tmpDir, "plugins-bundled")
|
||||
exists, err := fs.Exists(tgtDir)
|
||||
exists, err := fsutil.Exists(tgtDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -550,7 +550,7 @@ func copyPlugins(ctx context.Context, v config.Variant, grafanaDir, tmpDir strin
|
||||
|
||||
wantExe = fmt.Sprintf("%s_%s", plugExe, sfx)
|
||||
log.Printf("The external plugin should contain an executable %q", wantExe)
|
||||
exists, err := fs.Exists(filepath.Join(srcDir, wantExe))
|
||||
exists, err := fsutil.Exists(filepath.Join(srcDir, wantExe))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -591,7 +591,7 @@ func copyPlugins(ctx context.Context, v config.Variant, grafanaDir, tmpDir strin
|
||||
}
|
||||
|
||||
log.Printf("Copying %q to %q", pth, dstPath)
|
||||
return fs.CopyFile(pth, dstPath)
|
||||
return fsutil.CopyFile(pth, dstPath)
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to copy external plugin %q to %q: %w", srcDir, dstDir, err)
|
||||
}
|
||||
@@ -610,7 +610,7 @@ func copyInternalPlugins(pluginsDir, tmpDir string) error {
|
||||
tgtDir := filepath.Join(tmpDir, "plugins-bundled", "internal")
|
||||
srcDir := filepath.Join(pluginsDir, "dist")
|
||||
|
||||
exists, err := fs.Exists(tgtDir)
|
||||
exists, err := fsutil.Exists(tgtDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -635,7 +635,7 @@ func copyInternalPlugins(pluginsDir, tmpDir string) error {
|
||||
|
||||
dstPath := filepath.Join(tgtDir, fi.Name())
|
||||
log.Printf("Copying internal plugin %q to %q...", srcPath, dstPath)
|
||||
if err := fs.CopyRecursive(srcPath, dstPath); err != nil {
|
||||
if err := fsutil.CopyRecursive(srcPath, dstPath); err != nil {
|
||||
return fmt.Errorf("failed to copy %q to %q: %w", srcPath, dstPath, err)
|
||||
}
|
||||
}
|
||||
@@ -696,7 +696,7 @@ func realPackageVariant(ctx context.Context, v config.Variant, edition config.Ed
|
||||
return fmt.Errorf("failed to create tools dir %q: %w", toolsDir, err)
|
||||
}
|
||||
|
||||
if err := fs.CopyFile("/usr/local/go/lib/time/zoneinfo.zip",
|
||||
if err := fsutil.CopyFile("/usr/local/go/lib/time/zoneinfo.zip",
|
||||
filepath.Join(tmpDir, "tools", "zoneinfo.zip")); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -860,7 +860,7 @@ type linuxPackageOptions struct {
|
||||
// createArchive makes a distribution archive.
|
||||
func createArchive(srcDir string, edition config.Edition, v config.Variant, version, grafanaDir string) error {
|
||||
distDir := filepath.Join(grafanaDir, "dist")
|
||||
exists, err := fs.Exists(distDir)
|
||||
exists, err := fsutil.Exists(distDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/build/config"
|
||||
"github.com/grafana/grafana/pkg/build/errutil"
|
||||
"github.com/grafana/grafana/pkg/build/fsutil"
|
||||
"github.com/grafana/grafana/pkg/build/syncutil"
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
)
|
||||
|
||||
type PluginSigningMode = int
|
||||
@@ -45,7 +45,7 @@ func Build(ctx context.Context, grafanaDir string, p syncutil.WorkerPool, g *err
|
||||
}
|
||||
|
||||
dstPath := filepath.Join("plugins-bundled", "dist", fi.Name())
|
||||
if err := fs.CopyRecursive(filepath.Join(dpath, "dist"), dstPath); err != nil {
|
||||
if err := fsutil.CopyRecursive(filepath.Join(dpath, "dist"), dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if !verMode.PluginSignature.Sign {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type PackageJSON struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// Opens the package.json file in the provided directory and returns a struct that represents its contents
|
||||
func OpenPackageJSON(dir string) (PackageJSON, error) {
|
||||
f, err := os.Open(filepath.Clean(dir + "/package.json"))
|
||||
if err != nil {
|
||||
return PackageJSON{}, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Println("error closing package.json", err)
|
||||
}
|
||||
}()
|
||||
|
||||
jsonObj := PackageJSON{}
|
||||
if err := json.NewDecoder(f).Decode(&jsonObj); err != nil {
|
||||
return PackageJSON{}, err
|
||||
}
|
||||
|
||||
return jsonObj, nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
Copyright (c) 2013 - 2015 The Xorm Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the {organization} nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE 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.
|
||||
@@ -1,348 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
||||
|
||||
func strconvErr(err error) error {
|
||||
if ne, ok := err.(*strconv.NumError); ok {
|
||||
return ne.Err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
} else {
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
func asString(src interface{}) string {
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
}
|
||||
rv := reflect.ValueOf(src)
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(rv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(rv.Uint(), 10)
|
||||
case reflect.Float64:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(rv.Bool())
|
||||
}
|
||||
return fmt.Sprintf("%v", src)
|
||||
}
|
||||
|
||||
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.AppendInt(buf, rv.Int(), 10), true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.AppendUint(buf, rv.Uint(), 10), true
|
||||
case reflect.Float32:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
|
||||
case reflect.Float64:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
|
||||
case reflect.Bool:
|
||||
return strconv.AppendBool(buf, rv.Bool()), true
|
||||
case reflect.String:
|
||||
s := rv.String()
|
||||
return append(buf, s...), true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// convertAssign copies to dest the value in src, converting it if possible.
|
||||
// An error is returned if the copy would result in loss of information.
|
||||
// dest should be a pointer type.
|
||||
func convertAssign(dest, src interface{}) error {
|
||||
// Common cases, without reflect.
|
||||
switch s := src.(type) {
|
||||
case string:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s)
|
||||
return nil
|
||||
}
|
||||
case []byte:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = string(s)
|
||||
return nil
|
||||
case *interface{}:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
case time.Time:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
*d = s.Format(time.RFC3339Nano)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s.Format(time.RFC3339Nano))
|
||||
return nil
|
||||
}
|
||||
case nil:
|
||||
switch d := dest.(type) {
|
||||
case *interface{}:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var sv reflect.Value
|
||||
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
sv = reflect.ValueOf(src)
|
||||
switch sv.Kind() {
|
||||
case reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
*d = asString(src)
|
||||
return nil
|
||||
}
|
||||
case *[]byte:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes(nil, sv); ok {
|
||||
*d = b
|
||||
return nil
|
||||
}
|
||||
case *bool:
|
||||
bv, err := driver.Bool.ConvertValue(src)
|
||||
if err == nil {
|
||||
*d = bv.(bool)
|
||||
}
|
||||
return err
|
||||
case *interface{}:
|
||||
*d = src
|
||||
return nil
|
||||
}
|
||||
|
||||
dpv := reflect.ValueOf(dest)
|
||||
if dpv.Kind() != reflect.Ptr {
|
||||
return errors.New("destination not a pointer")
|
||||
}
|
||||
if dpv.IsNil() {
|
||||
return errNilPtr
|
||||
}
|
||||
|
||||
if !sv.IsValid() {
|
||||
sv = reflect.ValueOf(src)
|
||||
}
|
||||
|
||||
dv := reflect.Indirect(dpv)
|
||||
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
|
||||
switch b := src.(type) {
|
||||
case []byte:
|
||||
dv.Set(reflect.ValueOf(cloneBytes(b)))
|
||||
default:
|
||||
dv.Set(sv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
|
||||
dv.Set(sv.Convert(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
switch dv.Kind() {
|
||||
case reflect.Ptr:
|
||||
if src == nil {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
dv.Set(reflect.New(dv.Type().Elem()))
|
||||
return convertAssign(dv.Interface(), src)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
s := asString(src)
|
||||
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetInt(i64)
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
s := asString(src)
|
||||
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetUint(u64)
|
||||
return nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
s := asString(src)
|
||||
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetFloat(f64)
|
||||
return nil
|
||||
case reflect.String:
|
||||
dv.SetString(asString(src))
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
|
||||
}
|
||||
|
||||
func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
|
||||
switch tp.Kind() {
|
||||
case reflect.Int64:
|
||||
return vv.Int(), nil
|
||||
case reflect.Int:
|
||||
return int(vv.Int()), nil
|
||||
case reflect.Int32:
|
||||
return int32(vv.Int()), nil
|
||||
case reflect.Int16:
|
||||
return int16(vv.Int()), nil
|
||||
case reflect.Int8:
|
||||
return int8(vv.Int()), nil
|
||||
case reflect.Uint64:
|
||||
return vv.Uint(), nil
|
||||
case reflect.Uint:
|
||||
return uint(vv.Uint()), nil
|
||||
case reflect.Uint32:
|
||||
return uint32(vv.Uint()), nil
|
||||
case reflect.Uint16:
|
||||
return uint16(vv.Uint()), nil
|
||||
case reflect.Uint8:
|
||||
return uint8(vv.Uint()), nil
|
||||
case reflect.String:
|
||||
return vv.String(), nil
|
||||
case reflect.Slice:
|
||||
if tp.Elem().Kind() == reflect.Uint8 {
|
||||
v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
|
||||
}
|
||||
|
||||
func convertFloat(v interface{}) (float64, error) {
|
||||
switch v.(type) {
|
||||
case float32:
|
||||
return float64(v.(float32)), nil
|
||||
case float64:
|
||||
return v.(float64), nil
|
||||
case string:
|
||||
i, err := strconv.ParseFloat(v.(string), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
case []byte:
|
||||
i, err := strconv.ParseFloat(string(v.([]byte)), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported type: %v", v)
|
||||
}
|
||||
|
||||
func convertInt(v interface{}) (int64, error) {
|
||||
switch v.(type) {
|
||||
case int:
|
||||
return int64(v.(int)), nil
|
||||
case int8:
|
||||
return int64(v.(int8)), nil
|
||||
case int16:
|
||||
return int64(v.(int16)), nil
|
||||
case int32:
|
||||
return int64(v.(int32)), nil
|
||||
case int64:
|
||||
return v.(int64), nil
|
||||
case []byte:
|
||||
i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
case string:
|
||||
i, err := strconv.ParseInt(v.(string), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unsupported type: %v", v)
|
||||
}
|
||||
|
||||
func asBool(bs []byte) (bool, error) {
|
||||
if len(bs) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
if bs[0] == 0x00 {
|
||||
return false, nil
|
||||
} else if bs[0] == 0x01 {
|
||||
return true, nil
|
||||
}
|
||||
return strconv.ParseBool(string(bs))
|
||||
}
|
||||
@@ -1,639 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
var (
|
||||
mysqlReservedWords = map[string]bool{
|
||||
"ADD": true,
|
||||
"ALL": true,
|
||||
"ALTER": true,
|
||||
"ANALYZE": true,
|
||||
"AND": true,
|
||||
"AS": true,
|
||||
"ASC": true,
|
||||
"ASENSITIVE": true,
|
||||
"BEFORE": true,
|
||||
"BETWEEN": true,
|
||||
"BIGINT": true,
|
||||
"BINARY": true,
|
||||
"BLOB": true,
|
||||
"BOTH": true,
|
||||
"BY": true,
|
||||
"CALL": true,
|
||||
"CASCADE": true,
|
||||
"CASE": true,
|
||||
"CHANGE": true,
|
||||
"CHAR": true,
|
||||
"CHARACTER": true,
|
||||
"CHECK": true,
|
||||
"COLLATE": true,
|
||||
"COLUMN": true,
|
||||
"CONDITION": true,
|
||||
"CONNECTION": true,
|
||||
"CONSTRAINT": true,
|
||||
"CONTINUE": true,
|
||||
"CONVERT": true,
|
||||
"CREATE": true,
|
||||
"CROSS": true,
|
||||
"CURRENT_DATE": true,
|
||||
"CURRENT_TIME": true,
|
||||
"CURRENT_TIMESTAMP": true,
|
||||
"CURRENT_USER": true,
|
||||
"CURSOR": true,
|
||||
"DATABASE": true,
|
||||
"DATABASES": true,
|
||||
"DAY_HOUR": true,
|
||||
"DAY_MICROSECOND": true,
|
||||
"DAY_MINUTE": true,
|
||||
"DAY_SECOND": true,
|
||||
"DEC": true,
|
||||
"DECIMAL": true,
|
||||
"DECLARE": true,
|
||||
"DEFAULT": true,
|
||||
"DELAYED": true,
|
||||
"DELETE": true,
|
||||
"DESC": true,
|
||||
"DESCRIBE": true,
|
||||
"DETERMINISTIC": true,
|
||||
"DISTINCT": true,
|
||||
"DISTINCTROW": true,
|
||||
"DIV": true,
|
||||
"DOUBLE": true,
|
||||
"DROP": true,
|
||||
"DUAL": true,
|
||||
"EACH": true,
|
||||
"ELSE": true,
|
||||
"ELSEIF": true,
|
||||
"ENCLOSED": true,
|
||||
"ESCAPED": true,
|
||||
"EXISTS": true,
|
||||
"EXIT": true,
|
||||
"EXPLAIN": true,
|
||||
"FALSE": true,
|
||||
"FETCH": true,
|
||||
"FLOAT": true,
|
||||
"FLOAT4": true,
|
||||
"FLOAT8": true,
|
||||
"FOR": true,
|
||||
"FORCE": true,
|
||||
"FOREIGN": true,
|
||||
"FROM": true,
|
||||
"FULLTEXT": true,
|
||||
"GOTO": true,
|
||||
"GRANT": true,
|
||||
"GROUP": true,
|
||||
"HAVING": true,
|
||||
"HIGH_PRIORITY": true,
|
||||
"HOUR_MICROSECOND": true,
|
||||
"HOUR_MINUTE": true,
|
||||
"HOUR_SECOND": true,
|
||||
"IF": true,
|
||||
"IGNORE": true,
|
||||
"IN": true, "INDEX": true,
|
||||
"INFILE": true, "INNER": true, "INOUT": true,
|
||||
"INSENSITIVE": true, "INSERT": true, "INT": true,
|
||||
"INT1": true, "INT2": true, "INT3": true,
|
||||
"INT4": true, "INT8": true, "INTEGER": true,
|
||||
"INTERVAL": true, "INTO": true, "IS": true,
|
||||
"ITERATE": true, "JOIN": true, "KEY": true,
|
||||
"KEYS": true, "KILL": true, "LABEL": true,
|
||||
"LEADING": true, "LEAVE": true, "LEFT": true,
|
||||
"LIKE": true, "LIMIT": true, "LINEAR": true,
|
||||
"LINES": true, "LOAD": true, "LOCALTIME": true,
|
||||
"LOCALTIMESTAMP": true, "LOCK": true, "LONG": true,
|
||||
"LONGBLOB": true, "LONGTEXT": true, "LOOP": true,
|
||||
"LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true,
|
||||
"MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true,
|
||||
"MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true,
|
||||
"MODIFIES": true, "NATURAL": true, "NOT": true,
|
||||
"NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true,
|
||||
"ON OPTIMIZE": true, "OPTION": true,
|
||||
"OPTIONALLY": true, "OR": true, "ORDER": true,
|
||||
"OUT": true, "OUTER": true, "OUTFILE": true,
|
||||
"PRECISION": true, "PRIMARY": true, "PROCEDURE": true,
|
||||
"PURGE": true, "RAID0": true, "RANGE": true,
|
||||
"READ": true, "READS": true, "REAL": true,
|
||||
"REFERENCES": true, "REGEXP": true, "RELEASE": true,
|
||||
"RENAME": true, "REPEAT": true, "REPLACE": true,
|
||||
"REQUIRE": true, "RESTRICT": true, "RETURN": true,
|
||||
"REVOKE": true, "RIGHT": true, "RLIKE": true,
|
||||
"SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true,
|
||||
"SELECT": true, "SENSITIVE": true, "SEPARATOR": true,
|
||||
"SET": true, "SHOW": true, "SMALLINT": true,
|
||||
"SPATIAL": true, "SPECIFIC": true, "SQL": true,
|
||||
"SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true,
|
||||
"SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true,
|
||||
"SSL": true, "STARTING": true, "STRAIGHT_JOIN": true,
|
||||
"TABLE": true, "TERMINATED": true, "THEN": true,
|
||||
"TINYBLOB": true, "TINYINT": true, "TINYTEXT": true,
|
||||
"TO": true, "TRAILING": true, "TRIGGER": true,
|
||||
"TRUE": true, "UNDO": true, "UNION": true,
|
||||
"UNIQUE": true, "UNLOCK": true, "UNSIGNED": true,
|
||||
"UPDATE": true, "USAGE": true, "USE": true,
|
||||
"USING": true, "UTC_DATE": true, "UTC_TIME": true,
|
||||
"UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true,
|
||||
"VARCHAR": true,
|
||||
"VARCHARACTER": true,
|
||||
"VARYING": true,
|
||||
"WHEN": true,
|
||||
"WHERE": true,
|
||||
"WHILE": true,
|
||||
"WITH": true,
|
||||
"WRITE": true,
|
||||
"X509": true,
|
||||
"XOR": true,
|
||||
"YEAR_MONTH": true,
|
||||
"ZEROFILL": true,
|
||||
}
|
||||
)
|
||||
|
||||
type mysql struct {
|
||||
core.Base
|
||||
rowFormat string
|
||||
}
|
||||
|
||||
func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
}
|
||||
|
||||
func (db *mysql) SetParams(params map[string]string) {
|
||||
rowFormat, ok := params["rowFormat"]
|
||||
if ok {
|
||||
var t = strings.ToUpper(rowFormat)
|
||||
switch t {
|
||||
case "COMPACT":
|
||||
fallthrough
|
||||
case "REDUNDANT":
|
||||
fallthrough
|
||||
case "DYNAMIC":
|
||||
fallthrough
|
||||
case "COMPRESSED":
|
||||
db.rowFormat = t
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (db *mysql) SqlType(c *core.Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.Bool:
|
||||
res = core.TinyInt
|
||||
c.Length = 1
|
||||
case core.Serial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
c.Nullable = false
|
||||
res = core.Int
|
||||
case core.BigSerial:
|
||||
c.IsAutoIncrement = true
|
||||
c.IsPrimaryKey = true
|
||||
c.Nullable = false
|
||||
res = core.BigInt
|
||||
case core.Bytea:
|
||||
res = core.Blob
|
||||
case core.TimeStampz:
|
||||
res = core.Char
|
||||
c.Length = 64
|
||||
case core.Enum: // mysql enum
|
||||
res = core.Enum
|
||||
res += "("
|
||||
opts := ""
|
||||
for v := range c.EnumOptions {
|
||||
opts += fmt.Sprintf(",'%v'", v)
|
||||
}
|
||||
res += strings.TrimLeft(opts, ",")
|
||||
res += ")"
|
||||
case core.Set: // mysql set
|
||||
res = core.Set
|
||||
res += "("
|
||||
opts := ""
|
||||
for v := range c.SetOptions {
|
||||
opts += fmt.Sprintf(",'%v'", v)
|
||||
}
|
||||
res += strings.TrimLeft(opts, ",")
|
||||
res += ")"
|
||||
case core.NVarchar:
|
||||
res = core.Varchar
|
||||
case core.Uuid:
|
||||
res = core.Varchar
|
||||
c.Length = 40
|
||||
case core.Json:
|
||||
res = core.Text
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
||||
hasLen1 := (c.Length > 0)
|
||||
hasLen2 := (c.Length2 > 0)
|
||||
|
||||
if res == core.BigInt && !hasLen1 && !hasLen2 {
|
||||
c.Length = 20
|
||||
hasLen1 = true
|
||||
}
|
||||
|
||||
if hasLen2 {
|
||||
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
|
||||
} else if hasLen1 {
|
||||
res += "(" + strconv.Itoa(c.Length) + ")"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (db *mysql) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) IsReserved(name string) bool {
|
||||
_, ok := mysqlReservedWords[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *mysql) Quote(name string) string {
|
||||
return "`" + name + "`"
|
||||
}
|
||||
|
||||
func (db *mysql) SupportEngine() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) AutoIncrStr() string {
|
||||
return "AUTO_INCREMENT"
|
||||
}
|
||||
|
||||
func (db *mysql) SupportCharset() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) IndexOnTable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{db.DbName, tableName, idxName}
|
||||
sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
|
||||
sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
|
||||
return sql, args
|
||||
}
|
||||
|
||||
/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{db.DbName, tableName, colName}
|
||||
sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
|
||||
return sql, args
|
||||
}*/
|
||||
|
||||
func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{db.DbName, tableName}
|
||||
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
|
||||
return sql, args
|
||||
}
|
||||
|
||||
func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
args := []interface{}{db.DbName, tableName}
|
||||
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
|
||||
" `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
cols := make(map[string]*core.Column)
|
||||
colSeq := make([]string, 0)
|
||||
for rows.Next() {
|
||||
col := new(core.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
|
||||
var columnName, isNullable, colType, colKey, extra, comment string
|
||||
var colDefault *string
|
||||
err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
col.Name = strings.Trim(columnName, "` ")
|
||||
col.Comment = comment
|
||||
if isNullable == "YES" {
|
||||
col.Nullable = true
|
||||
}
|
||||
|
||||
if colDefault != nil {
|
||||
col.Default = *colDefault
|
||||
col.DefaultIsEmpty = false
|
||||
} else {
|
||||
col.DefaultIsEmpty = true
|
||||
}
|
||||
|
||||
cts := strings.Split(colType, "(")
|
||||
colName := cts[0]
|
||||
colType = strings.ToUpper(colName)
|
||||
var len1, len2 int
|
||||
if len(cts) == 2 {
|
||||
idx := strings.Index(cts[1], ")")
|
||||
if colType == core.Enum && cts[1][0] == '\'' { // enum
|
||||
options := strings.Split(cts[1][0:idx], ",")
|
||||
col.EnumOptions = make(map[string]int)
|
||||
for k, v := range options {
|
||||
v = strings.TrimSpace(v)
|
||||
v = strings.Trim(v, "'")
|
||||
col.EnumOptions[v] = k
|
||||
}
|
||||
} else if colType == core.Set && cts[1][0] == '\'' {
|
||||
options := strings.Split(cts[1][0:idx], ",")
|
||||
col.SetOptions = make(map[string]int)
|
||||
for k, v := range options {
|
||||
v = strings.TrimSpace(v)
|
||||
v = strings.Trim(v, "'")
|
||||
col.SetOptions[v] = k
|
||||
}
|
||||
} else {
|
||||
lens := strings.Split(cts[1][0:idx], ",")
|
||||
len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(lens) == 2 {
|
||||
len2, err = strconv.Atoi(lens[1])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if colType == "FLOAT UNSIGNED" {
|
||||
colType = "FLOAT"
|
||||
}
|
||||
if colType == "DOUBLE UNSIGNED" {
|
||||
colType = "DOUBLE"
|
||||
}
|
||||
col.Length = len1
|
||||
col.Length2 = len2
|
||||
if _, ok := core.SqlTypes[colType]; ok {
|
||||
col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("unknown colType %v", colType)
|
||||
}
|
||||
|
||||
if colKey == "PRI" {
|
||||
col.IsPrimaryKey = true
|
||||
}
|
||||
|
||||
if extra == "auto_increment" {
|
||||
col.IsAutoIncrement = true
|
||||
}
|
||||
|
||||
if !col.DefaultIsEmpty {
|
||||
if col.SQLType.IsText() {
|
||||
col.Default = "'" + col.Default + "'"
|
||||
} else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" {
|
||||
col.Default = "'" + col.Default + "'"
|
||||
}
|
||||
}
|
||||
cols[col.Name] = col
|
||||
colSeq = append(colSeq, col.Name)
|
||||
}
|
||||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *mysql) GetTables() ([]*core.Table, error) {
|
||||
args := []interface{}{db.DbName}
|
||||
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
|
||||
"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
var name, engine, tableRows, comment string
|
||||
var autoIncr *string
|
||||
err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
table.Name = name
|
||||
table.Comment = comment
|
||||
table.StoreEngine = engine
|
||||
tables = append(tables, table)
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
args := []interface{}{db.DbName, tableName}
|
||||
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
for rows.Next() {
|
||||
var indexType int
|
||||
var indexName, colName, nonUnique string
|
||||
err = rows.Scan(&indexName, &nonUnique, &colName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if indexName == "PRIMARY" {
|
||||
continue
|
||||
}
|
||||
|
||||
if nonUnique == "YES" || nonUnique == "1" {
|
||||
indexType = core.IndexType
|
||||
} else {
|
||||
indexType = core.UniqueType
|
||||
}
|
||||
|
||||
colName = strings.Trim(colName, "` ")
|
||||
var isRegular bool
|
||||
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
|
||||
indexName = indexName[5+len(tableName):]
|
||||
isRegular = true
|
||||
}
|
||||
|
||||
var index *core.Index
|
||||
var ok bool
|
||||
if index, ok = indexes[indexName]; !ok {
|
||||
index = new(core.Index)
|
||||
index.IsRegular = isRegular
|
||||
index.Type = indexType
|
||||
index.Name = indexName
|
||||
indexes[indexName] = index
|
||||
}
|
||||
index.AddColumn(colName)
|
||||
}
|
||||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
|
||||
var sql string
|
||||
sql = "CREATE TABLE IF NOT EXISTS "
|
||||
if tableName == "" {
|
||||
tableName = table.Name
|
||||
}
|
||||
|
||||
sql += db.Quote(tableName)
|
||||
sql += " ("
|
||||
|
||||
if len(table.ColumnsSeq()) > 0 {
|
||||
pkList := table.PrimaryKeys
|
||||
|
||||
for _, colName := range table.ColumnsSeq() {
|
||||
col := table.GetColumn(colName)
|
||||
if col.IsPrimaryKey && len(pkList) == 1 {
|
||||
sql += col.String(db)
|
||||
} else {
|
||||
sql += col.StringNoPk(db)
|
||||
}
|
||||
sql = strings.TrimSpace(sql)
|
||||
if len(col.Comment) > 0 {
|
||||
sql += " COMMENT '" + col.Comment + "'"
|
||||
}
|
||||
sql += ", "
|
||||
}
|
||||
|
||||
if len(pkList) > 1 {
|
||||
sql += "PRIMARY KEY ( "
|
||||
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
|
||||
sql += " ), "
|
||||
}
|
||||
|
||||
sql = sql[:len(sql)-2]
|
||||
}
|
||||
sql += ")"
|
||||
|
||||
if storeEngine != "" {
|
||||
sql += " ENGINE=" + storeEngine
|
||||
}
|
||||
|
||||
if len(charset) == 0 {
|
||||
charset = db.URI().Charset
|
||||
}
|
||||
if len(charset) != 0 {
|
||||
sql += " DEFAULT CHARSET " + charset
|
||||
}
|
||||
|
||||
if db.rowFormat != "" {
|
||||
sql += " ROW_FORMAT=" + db.rowFormat
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
func (db *mysql) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}}
|
||||
}
|
||||
|
||||
type mymysqlDriver struct {
|
||||
}
|
||||
|
||||
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
db := &core.Uri{DbType: core.MYSQL}
|
||||
|
||||
pd := strings.SplitN(dataSourceName, "*", 2)
|
||||
if len(pd) == 2 {
|
||||
// Parse protocol part of URI
|
||||
p := strings.SplitN(pd[0], ":", 2)
|
||||
if len(p) != 2 {
|
||||
return nil, errors.New("wrong protocol part of URI")
|
||||
}
|
||||
db.Proto = p[0]
|
||||
options := strings.Split(p[1], ",")
|
||||
db.Raddr = options[0]
|
||||
for _, o := range options[1:] {
|
||||
kv := strings.SplitN(o, "=", 2)
|
||||
var k, v string
|
||||
if len(kv) == 2 {
|
||||
k, v = kv[0], kv[1]
|
||||
} else {
|
||||
k, v = o, "true"
|
||||
}
|
||||
switch k {
|
||||
case "laddr":
|
||||
db.Laddr = v
|
||||
case "timeout":
|
||||
to, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.Timeout = to
|
||||
default:
|
||||
return nil, errors.New("Unknown option: " + k)
|
||||
}
|
||||
}
|
||||
// Remove protocol part
|
||||
pd = pd[1:]
|
||||
}
|
||||
// Parse database part of URI
|
||||
dup := strings.SplitN(pd[0], "/", 3)
|
||||
if len(dup) != 3 {
|
||||
return nil, errors.New("wrong database part of URI")
|
||||
}
|
||||
db.DbName = dup[0]
|
||||
db.User = dup[1]
|
||||
db.Passwd = dup[2]
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
type mysqlDriver struct {
|
||||
}
|
||||
|
||||
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
dsnPattern := regexp.MustCompile(
|
||||
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
|
||||
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
|
||||
`\/(?P<dbname>.*?)` + // /dbname
|
||||
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN]
|
||||
matches := dsnPattern.FindStringSubmatch(dataSourceName)
|
||||
names := dsnPattern.SubexpNames()
|
||||
|
||||
uri := &core.Uri{DbType: core.MYSQL}
|
||||
|
||||
for i, match := range matches {
|
||||
switch names[i] {
|
||||
case "dbname":
|
||||
uri.DbName = match
|
||||
case "params":
|
||||
if len(match) > 0 {
|
||||
kvs := strings.Split(match, "&")
|
||||
for _, kv := range kvs {
|
||||
splits := strings.Split(kv, "=")
|
||||
if len(splits) == 2 {
|
||||
switch splits[0] {
|
||||
case "charset":
|
||||
uri.Charset = splits[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return uri, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,486 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
var (
|
||||
sqlite3ReservedWords = map[string]bool{
|
||||
"ABORT": true,
|
||||
"ACTION": true,
|
||||
"ADD": true,
|
||||
"AFTER": true,
|
||||
"ALL": true,
|
||||
"ALTER": true,
|
||||
"ANALYZE": true,
|
||||
"AND": true,
|
||||
"AS": true,
|
||||
"ASC": true,
|
||||
"ATTACH": true,
|
||||
"AUTOINCREMENT": true,
|
||||
"BEFORE": true,
|
||||
"BEGIN": true,
|
||||
"BETWEEN": true,
|
||||
"BY": true,
|
||||
"CASCADE": true,
|
||||
"CASE": true,
|
||||
"CAST": true,
|
||||
"CHECK": true,
|
||||
"COLLATE": true,
|
||||
"COLUMN": true,
|
||||
"COMMIT": true,
|
||||
"CONFLICT": true,
|
||||
"CONSTRAINT": true,
|
||||
"CREATE": true,
|
||||
"CROSS": true,
|
||||
"CURRENT_DATE": true,
|
||||
"CURRENT_TIME": true,
|
||||
"CURRENT_TIMESTAMP": true,
|
||||
"DATABASE": true,
|
||||
"DEFAULT": true,
|
||||
"DEFERRABLE": true,
|
||||
"DEFERRED": true,
|
||||
"DELETE": true,
|
||||
"DESC": true,
|
||||
"DETACH": true,
|
||||
"DISTINCT": true,
|
||||
"DROP": true,
|
||||
"EACH": true,
|
||||
"ELSE": true,
|
||||
"END": true,
|
||||
"ESCAPE": true,
|
||||
"EXCEPT": true,
|
||||
"EXCLUSIVE": true,
|
||||
"EXISTS": true,
|
||||
"EXPLAIN": true,
|
||||
"FAIL": true,
|
||||
"FOR": true,
|
||||
"FOREIGN": true,
|
||||
"FROM": true,
|
||||
"FULL": true,
|
||||
"GLOB": true,
|
||||
"GROUP": true,
|
||||
"HAVING": true,
|
||||
"IF": true,
|
||||
"IGNORE": true,
|
||||
"IMMEDIATE": true,
|
||||
"IN": true,
|
||||
"INDEX": true,
|
||||
"INDEXED": true,
|
||||
"INITIALLY": true,
|
||||
"INNER": true,
|
||||
"INSERT": true,
|
||||
"INSTEAD": true,
|
||||
"INTERSECT": true,
|
||||
"INTO": true,
|
||||
"IS": true,
|
||||
"ISNULL": true,
|
||||
"JOIN": true,
|
||||
"KEY": true,
|
||||
"LEFT": true,
|
||||
"LIKE": true,
|
||||
"LIMIT": true,
|
||||
"MATCH": true,
|
||||
"NATURAL": true,
|
||||
"NO": true,
|
||||
"NOT": true,
|
||||
"NOTNULL": true,
|
||||
"NULL": true,
|
||||
"OF": true,
|
||||
"OFFSET": true,
|
||||
"ON": true,
|
||||
"OR": true,
|
||||
"ORDER": true,
|
||||
"OUTER": true,
|
||||
"PLAN": true,
|
||||
"PRAGMA": true,
|
||||
"PRIMARY": true,
|
||||
"QUERY": true,
|
||||
"RAISE": true,
|
||||
"RECURSIVE": true,
|
||||
"REFERENCES": true,
|
||||
"REGEXP": true,
|
||||
"REINDEX": true,
|
||||
"RELEASE": true,
|
||||
"RENAME": true,
|
||||
"REPLACE": true,
|
||||
"RESTRICT": true,
|
||||
"RIGHT": true,
|
||||
"ROLLBACK": true,
|
||||
"ROW": true,
|
||||
"SAVEPOINT": true,
|
||||
"SELECT": true,
|
||||
"SET": true,
|
||||
"TABLE": true,
|
||||
"TEMP": true,
|
||||
"TEMPORARY": true,
|
||||
"THEN": true,
|
||||
"TO": true,
|
||||
"TRANSACTI": true,
|
||||
"TRIGGER": true,
|
||||
"UNION": true,
|
||||
"UNIQUE": true,
|
||||
"UPDATE": true,
|
||||
"USING": true,
|
||||
"VACUUM": true,
|
||||
"VALUES": true,
|
||||
"VIEW": true,
|
||||
"VIRTUAL": true,
|
||||
"WHEN": true,
|
||||
"WHERE": true,
|
||||
"WITH": true,
|
||||
"WITHOUT": true,
|
||||
}
|
||||
)
|
||||
|
||||
type sqlite3 struct {
|
||||
core.Base
|
||||
}
|
||||
|
||||
func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
|
||||
return db.Base.Init(d, db, uri, drivername, dataSourceName)
|
||||
}
|
||||
|
||||
func (db *sqlite3) SqlType(c *core.Column) string {
|
||||
switch t := c.SQLType.Name; t {
|
||||
case core.Bool:
|
||||
if c.Default == "true" {
|
||||
c.Default = "1"
|
||||
} else if c.Default == "false" {
|
||||
c.Default = "0"
|
||||
}
|
||||
return core.Integer
|
||||
case core.Date, core.DateTime, core.TimeStamp, core.Time:
|
||||
return core.DateTime
|
||||
case core.TimeStampz:
|
||||
return core.Text
|
||||
case core.Char, core.Varchar, core.NVarchar, core.TinyText,
|
||||
core.Text, core.MediumText, core.LongText, core.Json:
|
||||
return core.Text
|
||||
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt:
|
||||
return core.Integer
|
||||
case core.Float, core.Double, core.Real:
|
||||
return core.Real
|
||||
case core.Decimal, core.Numeric:
|
||||
return core.Numeric
|
||||
case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
|
||||
return core.Blob
|
||||
case core.Serial, core.BigSerial:
|
||||
c.IsPrimaryKey = true
|
||||
c.IsAutoIncrement = true
|
||||
c.Nullable = false
|
||||
return core.Integer
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func (db *sqlite3) FormatBytes(bs []byte) string {
|
||||
return fmt.Sprintf("X'%x'", bs)
|
||||
}
|
||||
|
||||
func (db *sqlite3) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *sqlite3) IsReserved(name string) bool {
|
||||
_, ok := sqlite3ReservedWords[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (db *sqlite3) Quote(name string) string {
|
||||
return "`" + name + "`"
|
||||
}
|
||||
|
||||
func (db *sqlite3) AutoIncrStr() string {
|
||||
return "AUTOINCREMENT"
|
||||
}
|
||||
|
||||
func (db *sqlite3) SupportEngine() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *sqlite3) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *sqlite3) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{idxName}
|
||||
return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
|
||||
}
|
||||
|
||||
func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName}
|
||||
return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
|
||||
}
|
||||
|
||||
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
|
||||
// var unique string
|
||||
quote := db.Quote
|
||||
idxName := index.Name
|
||||
|
||||
if !strings.HasPrefix(idxName, "UQE_") &&
|
||||
!strings.HasPrefix(idxName, "IDX_") {
|
||||
if index.Type == core.UniqueType {
|
||||
idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
|
||||
} else {
|
||||
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
|
||||
}
|
||||
|
||||
func (db *sqlite3) ForUpdateSql(query string) string {
|
||||
return query
|
||||
}
|
||||
|
||||
func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
|
||||
args := []interface{}{tableName}
|
||||
query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
|
||||
db.LogSQL(query, args)
|
||||
rows, err := db.DB().Query(query, args...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// splitColStr splits a sqlite col strings as fields
|
||||
func splitColStr(colStr string) []string {
|
||||
colStr = strings.TrimSpace(colStr)
|
||||
var results = make([]string, 0, 10)
|
||||
var lastIdx int
|
||||
var hasC, hasQuote bool
|
||||
for i, c := range colStr {
|
||||
if c == ' ' && !hasQuote {
|
||||
if hasC {
|
||||
results = append(results, colStr[lastIdx:i])
|
||||
hasC = false
|
||||
}
|
||||
} else {
|
||||
if c == '\'' {
|
||||
hasQuote = !hasQuote
|
||||
}
|
||||
if !hasC {
|
||||
lastIdx = i
|
||||
}
|
||||
hasC = true
|
||||
if i == len(colStr)-1 {
|
||||
results = append(results, colStr[lastIdx:i+1])
|
||||
}
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func parseString(colStr string) (*core.Column, error) {
|
||||
fields := splitColStr(colStr)
|
||||
col := new(core.Column)
|
||||
col.Indexes = make(map[string]int)
|
||||
col.Nullable = true
|
||||
col.DefaultIsEmpty = true
|
||||
|
||||
for idx, field := range fields {
|
||||
if idx == 0 {
|
||||
col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
|
||||
continue
|
||||
} else if idx == 1 {
|
||||
col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
|
||||
continue
|
||||
}
|
||||
switch field {
|
||||
case "PRIMARY":
|
||||
col.IsPrimaryKey = true
|
||||
case "AUTOINCREMENT":
|
||||
col.IsAutoIncrement = true
|
||||
case "NULL":
|
||||
if fields[idx-1] == "NOT" {
|
||||
col.Nullable = false
|
||||
} else {
|
||||
col.Nullable = true
|
||||
}
|
||||
case "DEFAULT":
|
||||
col.Default = fields[idx+1]
|
||||
col.DefaultIsEmpty = false
|
||||
}
|
||||
}
|
||||
return col, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
|
||||
db.LogSQL(s, args)
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var name string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
return nil, nil, errors.New("no table named " + tableName)
|
||||
}
|
||||
|
||||
nStart := strings.Index(name, "(")
|
||||
nEnd := strings.LastIndex(name, ")")
|
||||
reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`)
|
||||
colCreates := reg.FindAllString(name[nStart+1:nEnd], -1)
|
||||
cols := make(map[string]*core.Column)
|
||||
colSeq := make([]string, 0)
|
||||
|
||||
for _, colStr := range colCreates {
|
||||
reg = regexp.MustCompile(`,\s`)
|
||||
colStr = reg.ReplaceAllString(colStr, ",")
|
||||
if strings.HasPrefix(strings.TrimSpace(colStr), "PRIMARY KEY") {
|
||||
parts := strings.Split(strings.TrimSpace(colStr), "(")
|
||||
if len(parts) == 2 {
|
||||
pkCols := strings.Split(strings.TrimRight(strings.TrimSpace(parts[1]), ")"), ",")
|
||||
for _, pk := range pkCols {
|
||||
if col, ok := cols[strings.Trim(strings.TrimSpace(pk), "`")]; ok {
|
||||
col.IsPrimaryKey = true
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
col, err := parseString(colStr)
|
||||
if err != nil {
|
||||
return colSeq, cols, err
|
||||
}
|
||||
|
||||
cols[col.Name] = col
|
||||
colSeq = append(colSeq, col.Name)
|
||||
}
|
||||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) GetTables() ([]*core.Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT name FROM sqlite_master WHERE type='table'"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*core.Table, 0)
|
||||
for rows.Next() {
|
||||
table := core.NewEmptyTable()
|
||||
err = rows.Scan(&table.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if table.Name == "sqlite_sequence" {
|
||||
continue
|
||||
}
|
||||
tables = append(tables, table)
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
|
||||
db.LogSQL(s, args)
|
||||
|
||||
rows, err := db.DB().Query(s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string]*core.Index, 0)
|
||||
for rows.Next() {
|
||||
var tmpSQL sql.NullString
|
||||
err = rows.Scan(&tmpSQL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !tmpSQL.Valid {
|
||||
continue
|
||||
}
|
||||
sql := tmpSQL.String
|
||||
|
||||
index := new(core.Index)
|
||||
nNStart := strings.Index(sql, "INDEX")
|
||||
nNEnd := strings.Index(sql, "ON")
|
||||
if nNStart == -1 || nNEnd == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
|
||||
var isRegular bool
|
||||
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
|
||||
index.Name = indexName[5+len(tableName):]
|
||||
isRegular = true
|
||||
} else {
|
||||
index.Name = indexName
|
||||
}
|
||||
|
||||
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
|
||||
index.Type = core.UniqueType
|
||||
} else {
|
||||
index.Type = core.IndexType
|
||||
}
|
||||
|
||||
nStart := strings.Index(sql, "(")
|
||||
nEnd := strings.Index(sql, ")")
|
||||
colIndexes := strings.Split(sql[nStart+1:nEnd], ",")
|
||||
|
||||
index.Cols = make([]string, 0)
|
||||
for _, col := range colIndexes {
|
||||
index.Cols = append(index.Cols, strings.Trim(col, "` []"))
|
||||
}
|
||||
index.IsRegular = isRegular
|
||||
indexes[index.Name] = index
|
||||
}
|
||||
|
||||
return indexes, nil
|
||||
}
|
||||
|
||||
func (db *sqlite3) Filters() []core.Filter {
|
||||
return []core.Filter{&core.IdFilter{}}
|
||||
}
|
||||
|
||||
type sqlite3Driver struct {
|
||||
}
|
||||
|
||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
||||
if strings.Contains(dataSourceName, "?") {
|
||||
dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")]
|
||||
}
|
||||
|
||||
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
|
||||
}
|
||||
@@ -1,750 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Engine is the major struct of xorm, it means a database manager.
|
||||
// Commonly, an application only need one engine
|
||||
type Engine struct {
|
||||
db *core.DB
|
||||
dialect core.Dialect
|
||||
|
||||
ColumnMapper core.IMapper
|
||||
TableMapper core.IMapper
|
||||
TagIdentifier string
|
||||
Tables map[reflect.Type]*core.Table
|
||||
|
||||
mutex *sync.RWMutex
|
||||
Cacher core.Cacher
|
||||
|
||||
showSQL bool
|
||||
showExecTime bool
|
||||
|
||||
logger core.ILogger
|
||||
TZLocation *time.Location // The timezone of the application
|
||||
DatabaseTZ *time.Location // The timezone of the database
|
||||
|
||||
tagHandlers map[string]tagHandler
|
||||
|
||||
defaultContext context.Context
|
||||
}
|
||||
|
||||
// CondDeleted returns the conditions whether a record is soft deleted.
|
||||
func (engine *Engine) CondDeleted(col *core.Column) builder.Cond {
|
||||
var cond = builder.NewCond()
|
||||
if col.SQLType.IsNumeric() {
|
||||
cond = builder.Eq{col.Name: 0}
|
||||
}
|
||||
|
||||
if col.Nullable {
|
||||
cond = cond.Or(builder.IsNull{col.Name})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// ShowSQL show SQL statement or not on logger if log level is great than INFO
|
||||
func (engine *Engine) ShowSQL(show ...bool) {
|
||||
engine.logger.ShowSQL(show...)
|
||||
if len(show) == 0 {
|
||||
engine.showSQL = true
|
||||
} else {
|
||||
engine.showSQL = show[0]
|
||||
}
|
||||
}
|
||||
|
||||
// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
|
||||
func (engine *Engine) ShowExecTime(show ...bool) {
|
||||
if len(show) == 0 {
|
||||
engine.showExecTime = true
|
||||
} else {
|
||||
engine.showExecTime = show[0]
|
||||
}
|
||||
}
|
||||
|
||||
// SetLogger set the new logger
|
||||
func (engine *Engine) SetLogger(logger core.ILogger) {
|
||||
engine.logger = logger
|
||||
engine.showSQL = logger.IsShowSQL()
|
||||
engine.dialect.SetLogger(logger)
|
||||
}
|
||||
|
||||
// DriverName return the current sql driver's name
|
||||
func (engine *Engine) DriverName() string {
|
||||
return engine.dialect.DriverName()
|
||||
}
|
||||
|
||||
// DataSourceName return the current connection string
|
||||
func (engine *Engine) DataSourceName() string {
|
||||
return engine.dialect.DataSourceName()
|
||||
}
|
||||
|
||||
// SetMapper set the name mapping rules
|
||||
func (engine *Engine) SetMapper(mapper core.IMapper) {
|
||||
engine.SetTableMapper(mapper)
|
||||
engine.SetColumnMapper(mapper)
|
||||
}
|
||||
|
||||
// SetTableMapper set the table name mapping rule
|
||||
func (engine *Engine) SetTableMapper(mapper core.IMapper) {
|
||||
engine.TableMapper = mapper
|
||||
}
|
||||
|
||||
// SetColumnMapper set the column name mapping rule
|
||||
func (engine *Engine) SetColumnMapper(mapper core.IMapper) {
|
||||
engine.ColumnMapper = mapper
|
||||
}
|
||||
|
||||
// SupportInsertMany If engine's database support batch insert records like
|
||||
// "insert into user values (name, age), (name, age)".
|
||||
// When the return is ture, then engine.Insert(&users) will
|
||||
// generate batch sql and exeute.
|
||||
func (engine *Engine) SupportInsertMany() bool {
|
||||
return engine.dialect.SupportInsertMany()
|
||||
}
|
||||
|
||||
func (engine *Engine) quoteColumns(columnStr string) string {
|
||||
columns := strings.Split(columnStr, ",")
|
||||
for i := 0; i < len(columns); i++ {
|
||||
columns[i] = engine.Quote(strings.TrimSpace(columns[i]))
|
||||
}
|
||||
return strings.Join(columns, ",")
|
||||
}
|
||||
|
||||
// Quote Use QuoteStr quote the string sql
|
||||
func (engine *Engine) Quote(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if len(value) == 0 {
|
||||
return value
|
||||
}
|
||||
|
||||
buf := strings.Builder{}
|
||||
engine.QuoteTo(&buf, value)
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// QuoteTo quotes string and writes into the buffer
|
||||
func (engine *Engine) QuoteTo(buf *strings.Builder, value string) {
|
||||
if buf == nil {
|
||||
return
|
||||
}
|
||||
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
|
||||
quoteTo(buf, engine.dialect.Quote(""), value)
|
||||
}
|
||||
|
||||
func quoteTo(buf *strings.Builder, quotePair string, value string) {
|
||||
if len(quotePair) < 2 { // no quote
|
||||
_, _ = buf.WriteString(value)
|
||||
return
|
||||
}
|
||||
|
||||
prefix, suffix := quotePair[0], quotePair[1]
|
||||
|
||||
i := 0
|
||||
for i < len(value) {
|
||||
// start of a token; might be already quoted
|
||||
if value[i] == '.' {
|
||||
_ = buf.WriteByte('.')
|
||||
i++
|
||||
} else if value[i] == prefix || value[i] == '`' {
|
||||
// Has quotes; skip/normalize `name` to prefix+name+sufix
|
||||
var ch byte
|
||||
if value[i] == prefix {
|
||||
ch = suffix
|
||||
} else {
|
||||
ch = '`'
|
||||
}
|
||||
i++
|
||||
_ = buf.WriteByte(prefix)
|
||||
for ; i < len(value) && value[i] != ch; i++ {
|
||||
_ = buf.WriteByte(value[i])
|
||||
}
|
||||
_ = buf.WriteByte(suffix)
|
||||
i++
|
||||
} else {
|
||||
// Requires quotes
|
||||
_ = buf.WriteByte(prefix)
|
||||
for ; i < len(value) && value[i] != '.'; i++ {
|
||||
_ = buf.WriteByte(value[i])
|
||||
}
|
||||
_ = buf.WriteByte(suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (engine *Engine) quote(sql string) string {
|
||||
return engine.dialect.Quote(sql)
|
||||
}
|
||||
|
||||
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
|
||||
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
|
||||
engine.db.SetConnMaxLifetime(d)
|
||||
}
|
||||
|
||||
// SetMaxOpenConns is only available for go 1.2+
|
||||
func (engine *Engine) SetMaxOpenConns(conns int) {
|
||||
engine.db.SetMaxOpenConns(conns)
|
||||
}
|
||||
|
||||
// SetMaxIdleConns set the max idle connections on pool, default is 2
|
||||
func (engine *Engine) SetMaxIdleConns(conns int) {
|
||||
engine.db.SetMaxIdleConns(conns)
|
||||
}
|
||||
|
||||
// NewDB provides an interface to operate database directly
|
||||
func (engine *Engine) NewDB() (*core.DB, error) {
|
||||
return core.OpenDialect(engine.dialect)
|
||||
}
|
||||
|
||||
// DB return the wrapper of sql.DB
|
||||
func (engine *Engine) DB() *core.DB {
|
||||
return engine.db
|
||||
}
|
||||
|
||||
// Dialect return database dialect
|
||||
func (engine *Engine) Dialect() core.Dialect {
|
||||
return engine.dialect
|
||||
}
|
||||
|
||||
// NewSession New a session
|
||||
func (engine *Engine) NewSession() *Session {
|
||||
session := &Session{engine: engine}
|
||||
session.Init()
|
||||
return session
|
||||
}
|
||||
|
||||
// Close the engine
|
||||
func (engine *Engine) Close() error {
|
||||
return engine.db.Close()
|
||||
}
|
||||
|
||||
// Ping tests if database is alive
|
||||
func (engine *Engine) Ping() error {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.Ping()
|
||||
}
|
||||
|
||||
// SQL method let's you manually write raw SQL and operate
|
||||
// For example:
|
||||
//
|
||||
// engine.SQL("select * from user").Find(&users)
|
||||
//
|
||||
// This code will execute "select * from user" and set the records to users
|
||||
func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.SQL(query, args...)
|
||||
}
|
||||
|
||||
func (engine *Engine) loadTableInfo(table *core.Table) error {
|
||||
colSeq, cols, err := engine.dialect.GetColumns(table.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range colSeq {
|
||||
table.AddColumn(cols[name])
|
||||
}
|
||||
indexes, err := engine.dialect.GetIndexes(table.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
table.Indexes = indexes
|
||||
|
||||
for _, index := range indexes {
|
||||
for _, name := range index.Cols {
|
||||
if col := table.GetColumn(name); col != nil {
|
||||
col.Indexes[index.Name] = index.Type
|
||||
} else {
|
||||
return fmt.Errorf("unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DBMetas Retrieve all tables, columns, indexes' informations from database.
|
||||
func (engine *Engine) DBMetas() ([]*core.Table, error) {
|
||||
tables, err := engine.dialect.GetTables()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
if err = engine.loadTableInfo(table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// Where method provide a condition query
|
||||
func (engine *Engine) Where(query interface{}, args ...interface{}) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Where(query, args...)
|
||||
}
|
||||
|
||||
// ID method provoide a condition as (id) = ?
|
||||
func (engine *Engine) ID(id interface{}) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.ID(id)
|
||||
}
|
||||
|
||||
// Before apply before Processor, affected bean is passed to closure arg
|
||||
func (engine *Engine) Before(closures func(interface{})) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Before(closures)
|
||||
}
|
||||
|
||||
// After apply after insert Processor, affected bean is passed to closure arg
|
||||
func (engine *Engine) After(closures func(interface{})) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.After(closures)
|
||||
}
|
||||
|
||||
// Charset set charset when create table, only support mysql now
|
||||
func (engine *Engine) Charset(charset string) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Charset(charset)
|
||||
}
|
||||
|
||||
// StoreEngine set store engine when create table, only support mysql now
|
||||
func (engine *Engine) StoreEngine(storeEngine string) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.StoreEngine(storeEngine)
|
||||
}
|
||||
|
||||
// Table temporarily change the Get, Find, Update's table
|
||||
func (engine *Engine) Table(tableNameOrBean interface{}) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
return session.Table(tableNameOrBean)
|
||||
}
|
||||
|
||||
func (engine *Engine) autoMapType(v reflect.Value) (*core.Table, error) {
|
||||
t := v.Type()
|
||||
engine.mutex.Lock()
|
||||
defer engine.mutex.Unlock()
|
||||
table, ok := engine.Tables[t]
|
||||
if !ok {
|
||||
var err error
|
||||
table, err = engine.mapType(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
engine.Tables[t] = table
|
||||
if engine.Cacher != nil {
|
||||
if v.CanAddr() {
|
||||
engine.GobRegister(v.Addr().Interface())
|
||||
} else {
|
||||
engine.GobRegister(v.Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
return table, nil
|
||||
}
|
||||
|
||||
// GobRegister register one struct to gob for cache use
|
||||
func (engine *Engine) GobRegister(v interface{}) *Engine {
|
||||
gob.Register(v)
|
||||
return engine
|
||||
}
|
||||
|
||||
// Table table struct
|
||||
type Table struct {
|
||||
*core.Table
|
||||
Name string
|
||||
}
|
||||
|
||||
func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) {
|
||||
if index, ok := table.Indexes[indexName]; ok {
|
||||
index.AddColumn(col.Name)
|
||||
col.Indexes[index.Name] = indexType
|
||||
} else {
|
||||
index := core.NewIndex(indexName, indexType)
|
||||
index.AddColumn(col.Name)
|
||||
table.AddIndex(index)
|
||||
col.Indexes[index.Name] = indexType
|
||||
}
|
||||
}
|
||||
|
||||
// TableName table name interface to define customerize table name
|
||||
type TableName interface {
|
||||
TableName() string
|
||||
}
|
||||
|
||||
var (
|
||||
tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()
|
||||
)
|
||||
|
||||
func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
|
||||
t := v.Type()
|
||||
table := core.NewEmptyTable()
|
||||
table.Type = t
|
||||
table.Name = getTableName(engine.TableMapper, v)
|
||||
|
||||
var idFieldColName string
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
tag := t.Field(i).Tag
|
||||
|
||||
ormTagStr := tag.Get(engine.TagIdentifier)
|
||||
var col *core.Column
|
||||
fieldValue := v.Field(i)
|
||||
fieldType := fieldValue.Type()
|
||||
|
||||
if ormTagStr != "" {
|
||||
col = &core.Column{
|
||||
FieldName: t.Field(i).Name,
|
||||
Nullable: true,
|
||||
IsPrimaryKey: false,
|
||||
IsAutoIncrement: false,
|
||||
MapType: core.TWOSIDES,
|
||||
Indexes: make(map[string]int),
|
||||
DefaultIsEmpty: true,
|
||||
}
|
||||
tags := splitTag(ormTagStr)
|
||||
|
||||
if len(tags) > 0 {
|
||||
if tags[0] == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
var ctx = tagContext{
|
||||
table: table,
|
||||
col: col,
|
||||
fieldValue: fieldValue,
|
||||
indexNames: make(map[string]int),
|
||||
engine: engine,
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.ToUpper(tags[0]), "EXTENDS") {
|
||||
pStart := strings.Index(tags[0], "(")
|
||||
if pStart > -1 && strings.HasSuffix(tags[0], ")") {
|
||||
var tagPrefix = strings.TrimFunc(tags[0][pStart+1:len(tags[0])-1], func(r rune) bool {
|
||||
return r == '\'' || r == '"'
|
||||
})
|
||||
|
||||
ctx.params = []string{tagPrefix}
|
||||
}
|
||||
|
||||
if err := ExtendsTagHandler(&ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for j, key := range tags {
|
||||
if ctx.ignoreNext {
|
||||
ctx.ignoreNext = false
|
||||
continue
|
||||
}
|
||||
|
||||
k := strings.ToUpper(key)
|
||||
ctx.tagName = k
|
||||
ctx.params = []string{}
|
||||
|
||||
pStart := strings.Index(k, "(")
|
||||
if pStart == 0 {
|
||||
return nil, errors.New("( could not be the first character")
|
||||
}
|
||||
if pStart > -1 {
|
||||
if !strings.HasSuffix(k, ")") {
|
||||
return nil, fmt.Errorf("field %s tag %s cannot match ) character", col.FieldName, key)
|
||||
}
|
||||
|
||||
ctx.tagName = k[:pStart]
|
||||
ctx.params = strings.Split(key[pStart+1:len(k)-1], ",")
|
||||
}
|
||||
|
||||
if j > 0 {
|
||||
ctx.preTag = strings.ToUpper(tags[j-1])
|
||||
}
|
||||
if j < len(tags)-1 {
|
||||
ctx.nextTag = tags[j+1]
|
||||
} else {
|
||||
ctx.nextTag = ""
|
||||
}
|
||||
|
||||
if h, ok := engine.tagHandlers[ctx.tagName]; ok {
|
||||
if err := h(&ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if strings.HasPrefix(key, "'") && strings.HasSuffix(key, "'") {
|
||||
col.Name = key[1 : len(key)-1]
|
||||
} else {
|
||||
col.Name = key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if col.SQLType.Name == "" {
|
||||
col.SQLType = core.Type2SQLType(fieldType)
|
||||
}
|
||||
engine.dialect.SqlType(col)
|
||||
if col.Length == 0 {
|
||||
col.Length = col.SQLType.DefaultLength
|
||||
}
|
||||
if col.Length2 == 0 {
|
||||
col.Length2 = col.SQLType.DefaultLength2
|
||||
}
|
||||
if col.Name == "" {
|
||||
col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name)
|
||||
}
|
||||
|
||||
if ctx.isUnique {
|
||||
ctx.indexNames[col.Name] = core.UniqueType
|
||||
} else if ctx.isIndex {
|
||||
ctx.indexNames[col.Name] = core.IndexType
|
||||
}
|
||||
|
||||
for indexName, indexType := range ctx.indexNames {
|
||||
addIndex(indexName, table, col, indexType)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var sqlType core.SQLType
|
||||
if fieldValue.CanAddr() {
|
||||
if _, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
|
||||
sqlType = core.SQLType{Name: core.Text}
|
||||
}
|
||||
}
|
||||
if _, ok := fieldValue.Interface().(core.Conversion); ok {
|
||||
sqlType = core.SQLType{Name: core.Text}
|
||||
} else {
|
||||
sqlType = core.Type2SQLType(fieldType)
|
||||
}
|
||||
col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name),
|
||||
t.Field(i).Name, sqlType, sqlType.DefaultLength,
|
||||
sqlType.DefaultLength2, true)
|
||||
|
||||
if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
|
||||
idFieldColName = col.Name
|
||||
}
|
||||
}
|
||||
if col.IsAutoIncrement {
|
||||
col.Nullable = false
|
||||
}
|
||||
|
||||
table.AddColumn(col)
|
||||
|
||||
} // end for
|
||||
|
||||
if idFieldColName != "" && len(table.PrimaryKeys) == 0 {
|
||||
col := table.GetColumn(idFieldColName)
|
||||
col.IsPrimaryKey = true
|
||||
col.IsAutoIncrement = true
|
||||
col.Nullable = false
|
||||
table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
|
||||
table.AutoIncrement = col.Name
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
// IsTableExist if a table is exist
|
||||
func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.IsTableExist(beanOrTableName)
|
||||
}
|
||||
|
||||
// Sync the new struct changes to database, this method will automatically add
|
||||
// table, column, index, unique. but will not delete or change anything.
|
||||
// If you change some field, you should change the database manually.
|
||||
func (engine *Engine) Sync(beans ...interface{}) error {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
|
||||
for _, bean := range beans {
|
||||
v := rValue(bean)
|
||||
tableNameNoSchema := engine.TableName(bean)
|
||||
table, err := engine.autoMapType(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
err = session.createTable(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var isEmpty bool
|
||||
if isEmpty {
|
||||
err = session.dropTable(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = session.createTable(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, col := range table.Columns() {
|
||||
isExist, err := engine.dialect.IsColumnExist(tableNameNoSchema, col.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
err = session.addColumn(col.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for name, index := range table.Indexes {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
if index.Type == core.UniqueType {
|
||||
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = session.addUnique(tableNameNoSchema, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if index.Type == core.IndexType {
|
||||
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isExist {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = session.addIndex(tableNameNoSchema, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return errors.New("unknow index type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sync2 synchronize structs to database tables
|
||||
func (engine *Engine) Sync2(beans ...interface{}) error {
|
||||
s := engine.NewSession()
|
||||
defer s.Close()
|
||||
return s.Sync2(beans...)
|
||||
}
|
||||
|
||||
// Exec raw sql
|
||||
func (engine *Engine) Exec(sqlOrArgs ...interface{}) (sql.Result, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.Exec(sqlOrArgs...)
|
||||
}
|
||||
|
||||
// Insert one or more records
|
||||
func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.Insert(beans...)
|
||||
}
|
||||
|
||||
// Find retrieve records from table, condiBeans's non-empty fields
|
||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
|
||||
// map[int64]*Struct
|
||||
func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
|
||||
session := engine.NewSession()
|
||||
defer session.Close()
|
||||
return session.Find(beans, condiBeans...)
|
||||
}
|
||||
|
||||
// nowTime return current time
|
||||
func (engine *Engine) nowTime(col *core.Column) (interface{}, time.Time) {
|
||||
t := time.Now()
|
||||
var tz = engine.DatabaseTZ
|
||||
if !col.DisableTimeZone && col.TimeZone != nil {
|
||||
tz = col.TimeZone
|
||||
}
|
||||
return engine.formatTime(col.SQLType.Name, t.In(tz)), t.In(engine.TZLocation)
|
||||
}
|
||||
|
||||
func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) {
|
||||
if t.IsZero() {
|
||||
if col.Nullable {
|
||||
return nil
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
if col.TimeZone != nil {
|
||||
return engine.formatTime(col.SQLType.Name, t.In(col.TimeZone))
|
||||
}
|
||||
return engine.formatTime(col.SQLType.Name, t.In(engine.DatabaseTZ))
|
||||
}
|
||||
|
||||
// formatTime format time as column type
|
||||
func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) {
|
||||
switch sqlTypeName {
|
||||
case core.Time:
|
||||
s := t.Format("2006-01-02 15:04:05") // time.RFC3339
|
||||
v = s[11:19]
|
||||
case core.Date:
|
||||
v = t.Format("2006-01-02")
|
||||
case core.DateTime, core.TimeStamp, core.Varchar: // !DarthPestilane! format time when sqlTypeName is core.Varchar.
|
||||
v = t.Format("2006-01-02 15:04:05")
|
||||
case core.TimeStampz:
|
||||
v = t.Format(time.RFC3339Nano)
|
||||
case core.BigInt, core.Int:
|
||||
v = t.Unix()
|
||||
default:
|
||||
v = t
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func (engine *Engine) buildConds(table *core.Table, bean interface{},
|
||||
includeVersion bool, includeUpdated bool, includeNil bool,
|
||||
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
|
||||
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
|
||||
var conds []builder.Cond
|
||||
for _, col := range table.Columns() {
|
||||
if !includeVersion && col.IsVersion {
|
||||
continue
|
||||
}
|
||||
if !includeUpdated && col.IsUpdated {
|
||||
continue
|
||||
}
|
||||
if !includeAutoIncr && col.IsAutoIncrement {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.SQLType.IsJson() {
|
||||
continue
|
||||
}
|
||||
|
||||
var colName string
|
||||
if addedTableName {
|
||||
var nm = tableName
|
||||
if len(aliasName) > 0 {
|
||||
nm = aliasName
|
||||
}
|
||||
colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
|
||||
} else {
|
||||
colName = engine.Quote(col.Name)
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "is not valid") {
|
||||
engine.logger.Warn(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
|
||||
conds = append(conds, engine.CondDeleted(col))
|
||||
}
|
||||
|
||||
fieldValue := *fieldValuePtr
|
||||
if fieldValue.Interface() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldType := reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField := useAllCols
|
||||
|
||||
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
|
||||
if b {
|
||||
requiredField = true
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if fieldType.Kind() == reflect.Ptr {
|
||||
if fieldValue.IsNil() {
|
||||
if includeNil {
|
||||
conds = append(conds, builder.Eq{colName: nil})
|
||||
}
|
||||
continue
|
||||
} else if !fieldValue.IsValid() {
|
||||
continue
|
||||
} else {
|
||||
// dereference ptr type to instance type
|
||||
fieldValue = fieldValue.Elem()
|
||||
fieldType = reflect.TypeOf(fieldValue.Interface())
|
||||
requiredField = true
|
||||
}
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Bool:
|
||||
if allUseBool || requiredField {
|
||||
val = fieldValue.Interface()
|
||||
} else {
|
||||
// if a bool in a struct, it will not be as a condition because it default is false,
|
||||
// please use Where() instead
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if !requiredField && fieldValue.String() == "" {
|
||||
continue
|
||||
}
|
||||
// for MyString, should convert to string or panic
|
||||
if fieldType.String() != reflect.String.String() {
|
||||
val = fieldValue.String()
|
||||
} else {
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
|
||||
if !requiredField && fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if !requiredField && fieldValue.Float() == 0.0 {
|
||||
continue
|
||||
}
|
||||
val = fieldValue.Interface()
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
|
||||
if !requiredField && fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
t := int64(fieldValue.Uint())
|
||||
val = reflect.ValueOf(&t).Interface()
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
|
||||
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
|
||||
continue
|
||||
}
|
||||
val = engine.formatColTime(col, t)
|
||||
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
|
||||
continue
|
||||
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
val, _ = valNul.Value()
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if col.SQLType.IsJson() {
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
engine.autoMapType(fieldValue)
|
||||
if table, ok := engine.Tables[fieldValue.Type()]; ok {
|
||||
if len(table.PrimaryKeys) == 1 {
|
||||
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
|
||||
// fix non-int pk issues
|
||||
//if pkField.Int() != 0 {
|
||||
if pkField.IsValid() && !isZero(pkField.Interface()) {
|
||||
val = pkField.Interface()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
//TODO: how to handler?
|
||||
return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
|
||||
}
|
||||
} else {
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Array:
|
||||
continue
|
||||
case reflect.Slice, reflect.Map:
|
||||
if fieldValue == reflect.Zero(fieldType) {
|
||||
continue
|
||||
}
|
||||
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = string(bytes)
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
|
||||
fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
if fieldValue.Len() > 0 {
|
||||
val = fieldValue.Bytes()
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
engine.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
val = bytes
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
val = fieldValue.Interface()
|
||||
}
|
||||
|
||||
conds = append(conds, builder.Eq{colName: val})
|
||||
}
|
||||
|
||||
return builder.And(conds...), nil
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright 2018 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// tbNameWithSchema will automatically add schema prefix on table name
|
||||
func (engine *Engine) tbNameWithSchema(v string) string {
|
||||
// Add schema name as prefix of table name.
|
||||
// Only for postgres database.
|
||||
if engine.dialect.DBType() == core.POSTGRES &&
|
||||
engine.dialect.URI().Schema != "" &&
|
||||
engine.dialect.URI().Schema != postgresPublicSchema &&
|
||||
!strings.Contains(v, ".") {
|
||||
return engine.dialect.URI().Schema + "." + v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func isSubQuery(tbName string) bool {
|
||||
const selStr = "select"
|
||||
if len(tbName) <= len(selStr)+1 {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.EqualFold(tbName[:len(selStr)], selStr) || strings.EqualFold(tbName[:len(selStr)+1], "("+selStr)
|
||||
}
|
||||
|
||||
// TableName returns table name with schema prefix if has
|
||||
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
|
||||
tbName := engine.tbNameNoSchema(bean)
|
||||
if len(includeSchema) > 0 && includeSchema[0] && !isSubQuery(tbName) {
|
||||
tbName = engine.tbNameWithSchema(tbName)
|
||||
}
|
||||
return tbName
|
||||
}
|
||||
|
||||
func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
|
||||
switch tablename.(type) {
|
||||
case []string:
|
||||
t := tablename.([]string)
|
||||
if len(t) > 1 {
|
||||
return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
|
||||
} else if len(t) == 1 {
|
||||
return engine.Quote(t[0])
|
||||
}
|
||||
case []interface{}:
|
||||
t := tablename.([]interface{})
|
||||
l := len(t)
|
||||
var table string
|
||||
if l > 0 {
|
||||
f := t[0]
|
||||
switch f.(type) {
|
||||
case string:
|
||||
table = f.(string)
|
||||
case TableName:
|
||||
table = f.(TableName).TableName()
|
||||
default:
|
||||
v := rValue(f)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
table = getTableName(engine.TableMapper, v)
|
||||
} else {
|
||||
table = engine.Quote(fmt.Sprintf("%v", f))
|
||||
}
|
||||
}
|
||||
}
|
||||
if l > 1 {
|
||||
return fmt.Sprintf("%v AS %v", engine.Quote(table),
|
||||
engine.Quote(fmt.Sprintf("%v", t[1])))
|
||||
} else if l == 1 {
|
||||
return engine.Quote(table)
|
||||
}
|
||||
case TableName:
|
||||
return tablename.(TableName).TableName()
|
||||
case string:
|
||||
return tablename.(string)
|
||||
case reflect.Value:
|
||||
v := tablename.(reflect.Value)
|
||||
return getTableName(engine.TableMapper, v)
|
||||
default:
|
||||
v := rValue(tablename)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Struct {
|
||||
return getTableName(engine.TableMapper, v)
|
||||
}
|
||||
return engine.Quote(fmt.Sprintf("%v", tablename))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrParamsType params error
|
||||
ErrParamsType = errors.New("params type error")
|
||||
// ErrTableNotFound table not found error
|
||||
ErrTableNotFound = errors.New("table not found")
|
||||
// ErrUnSupportedType unsupported error
|
||||
ErrUnSupportedType = errors.New("unsupported type error")
|
||||
// ErrNotExist record does not exist error
|
||||
ErrNotExist = errors.New("record does not exist")
|
||||
// ErrCacheFailed cache failed error
|
||||
ErrCacheFailed = errors.New("cache failed")
|
||||
// ErrNeedDeletedCond delete needs less one condition error
|
||||
ErrNeedDeletedCond = errors.New("delete action needs at least one condition")
|
||||
// ErrNotImplemented not implemented
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
// ErrConditionType condition type unsupported
|
||||
ErrConditionType = errors.New("unsupported condition type")
|
||||
// ErrUnSupportedSQLType parameter of SQL is not supported
|
||||
ErrUnSupportedSQLType = errors.New("unsupported sql type")
|
||||
)
|
||||
|
||||
// ErrFieldIsNotExist columns does not exist
|
||||
type ErrFieldIsNotExist struct {
|
||||
FieldName string
|
||||
TableName string
|
||||
}
|
||||
|
||||
func (e ErrFieldIsNotExist) Error() string {
|
||||
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
|
||||
}
|
||||
|
||||
// ErrFieldIsNotValid is not valid
|
||||
type ErrFieldIsNotValid struct {
|
||||
FieldName string
|
||||
TableName string
|
||||
}
|
||||
|
||||
func (e ErrFieldIsNotValid) Error() string {
|
||||
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
module xorm.io/xorm
|
||||
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/ziutek/mymysql v1.5.4
|
||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
||||
xorm.io/builder v0.3.6
|
||||
xorm.io/core v0.7.2
|
||||
)
|
||||
@@ -1,151 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
|
||||
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
|
||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
@@ -1,209 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type zeroable interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
func isZero(k interface{}) bool {
|
||||
switch k.(type) {
|
||||
case int:
|
||||
return k.(int) == 0
|
||||
case int8:
|
||||
return k.(int8) == 0
|
||||
case int16:
|
||||
return k.(int16) == 0
|
||||
case int32:
|
||||
return k.(int32) == 0
|
||||
case int64:
|
||||
return k.(int64) == 0
|
||||
case uint:
|
||||
return k.(uint) == 0
|
||||
case uint8:
|
||||
return k.(uint8) == 0
|
||||
case uint16:
|
||||
return k.(uint16) == 0
|
||||
case uint32:
|
||||
return k.(uint32) == 0
|
||||
case uint64:
|
||||
return k.(uint64) == 0
|
||||
case float32:
|
||||
return k.(float32) == 0
|
||||
case float64:
|
||||
return k.(float64) == 0
|
||||
case bool:
|
||||
return k.(bool) == false
|
||||
case string:
|
||||
return k.(string) == ""
|
||||
case zeroable:
|
||||
return k.(zeroable).IsZero()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isZeroValue(v reflect.Value) bool {
|
||||
if isZero(v.Interface()) {
|
||||
return true
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return v.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isStructZero(v reflect.Value) bool {
|
||||
if !v.IsValid() {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
switch field.Kind() {
|
||||
case reflect.Ptr:
|
||||
field = field.Elem()
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
if !isStructZero(field) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if field.CanInterface() && !isZero(field.Interface()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func splitTag(tag string) (tags []string) {
|
||||
tag = strings.TrimSpace(tag)
|
||||
var hasQuote = false
|
||||
var lastIdx = 0
|
||||
for i, t := range tag {
|
||||
if t == '\'' {
|
||||
hasQuote = !hasQuote
|
||||
} else if t == ' ' {
|
||||
if lastIdx < i && !hasQuote {
|
||||
tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
|
||||
lastIdx = i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if lastIdx < len(tag) {
|
||||
tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isArrayValueZero(v reflect.Value) bool {
|
||||
if !v.IsValid() || v.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if !isZero(v.Index(i).Interface()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
|
||||
var v interface{}
|
||||
kind := tp.Kind()
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
kind = tp.Elem().Kind()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Int16:
|
||||
temp := int16(id)
|
||||
v = &temp
|
||||
case reflect.Int32:
|
||||
temp := int32(id)
|
||||
v = &temp
|
||||
case reflect.Int:
|
||||
temp := int(id)
|
||||
v = &temp
|
||||
case reflect.Int64:
|
||||
temp := id
|
||||
v = &temp
|
||||
case reflect.Uint16:
|
||||
temp := uint16(id)
|
||||
v = &temp
|
||||
case reflect.Uint32:
|
||||
temp := uint32(id)
|
||||
v = &temp
|
||||
case reflect.Uint64:
|
||||
temp := uint64(id)
|
||||
v = &temp
|
||||
case reflect.Uint:
|
||||
temp := uint(id)
|
||||
v = &temp
|
||||
}
|
||||
|
||||
if tp.Kind() == reflect.Ptr {
|
||||
return reflect.ValueOf(v).Convert(tp)
|
||||
}
|
||||
return reflect.ValueOf(v).Elem().Convert(tp)
|
||||
}
|
||||
|
||||
func int64ToInt(id int64, tp reflect.Type) interface{} {
|
||||
return int64ToIntValue(id, tp).Interface()
|
||||
}
|
||||
|
||||
func rValue(bean interface{}) reflect.Value {
|
||||
return reflect.Indirect(reflect.ValueOf(bean))
|
||||
}
|
||||
|
||||
func sliceEq(left, right []string) bool {
|
||||
if len(left) != len(right) {
|
||||
return false
|
||||
}
|
||||
sort.Sort(sort.StringSlice(left))
|
||||
sort.Sort(sort.StringSlice(right))
|
||||
for i := 0; i < len(left); i++ {
|
||||
if left[i] != right[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func indexName(tableName, idxName string) string {
|
||||
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
|
||||
}
|
||||
|
||||
func eraseAny(value string, strToErase ...string) string {
|
||||
if len(strToErase) == 0 {
|
||||
return value
|
||||
}
|
||||
var replaceSeq []string
|
||||
for _, s := range strToErase {
|
||||
replaceSeq = append(replaceSeq, s, "")
|
||||
}
|
||||
|
||||
replacer := strings.NewReplacer(replaceSeq...)
|
||||
|
||||
return replacer.Replace(value)
|
||||
}
|
||||
|
||||
func quoteColumns(cols []string, quoteFunc func(string) string, sep string) string {
|
||||
for i := range cols {
|
||||
cols[i] = quoteFunc(cols[i])
|
||||
}
|
||||
return strings.Join(cols, sep+" ")
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// JSONInterface represents an interface to handle json data
|
||||
type JSONInterface interface {
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultJSONHandler default json handler
|
||||
DefaultJSONHandler JSONInterface = StdJSON{}
|
||||
)
|
||||
|
||||
// StdJSON implements JSONInterface via encoding/json
|
||||
type StdJSON struct{}
|
||||
|
||||
// Marshal implements JSONInterface
|
||||
func (StdJSON) Marshal(v interface{}) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// Unmarshal implements JSONInterface
|
||||
func (StdJSON) Unmarshal(data []byte, v interface{}) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// default log options
|
||||
const (
|
||||
DEFAULT_LOG_PREFIX = "[xorm]"
|
||||
DEFAULT_LOG_FLAG = log.Ldate | log.Lmicroseconds
|
||||
DEFAULT_LOG_LEVEL = core.LOG_DEBUG
|
||||
)
|
||||
|
||||
var _ core.ILogger = DiscardLogger{}
|
||||
|
||||
// DiscardLogger don't log implementation for core.ILogger
|
||||
type DiscardLogger struct{}
|
||||
|
||||
// Debug empty implementation
|
||||
func (DiscardLogger) Debug(v ...interface{}) {}
|
||||
|
||||
// Debugf empty implementation
|
||||
func (DiscardLogger) Debugf(format string, v ...interface{}) {}
|
||||
|
||||
// Error empty implementation
|
||||
func (DiscardLogger) Error(v ...interface{}) {}
|
||||
|
||||
// Errorf empty implementation
|
||||
func (DiscardLogger) Errorf(format string, v ...interface{}) {}
|
||||
|
||||
// Info empty implementation
|
||||
func (DiscardLogger) Info(v ...interface{}) {}
|
||||
|
||||
// Infof empty implementation
|
||||
func (DiscardLogger) Infof(format string, v ...interface{}) {}
|
||||
|
||||
// Warn empty implementation
|
||||
func (DiscardLogger) Warn(v ...interface{}) {}
|
||||
|
||||
// Warnf empty implementation
|
||||
func (DiscardLogger) Warnf(format string, v ...interface{}) {}
|
||||
|
||||
// Level empty implementation
|
||||
func (DiscardLogger) Level() core.LogLevel {
|
||||
return core.LOG_UNKNOWN
|
||||
}
|
||||
|
||||
// SetLevel empty implementation
|
||||
func (DiscardLogger) SetLevel(l core.LogLevel) {}
|
||||
|
||||
// ShowSQL empty implementation
|
||||
func (DiscardLogger) ShowSQL(show ...bool) {}
|
||||
|
||||
// IsShowSQL empty implementation
|
||||
func (DiscardLogger) IsShowSQL() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SimpleLogger is the default implment of core.ILogger
|
||||
type SimpleLogger struct {
|
||||
DEBUG *log.Logger
|
||||
ERR *log.Logger
|
||||
INFO *log.Logger
|
||||
WARN *log.Logger
|
||||
level core.LogLevel
|
||||
showSQL bool
|
||||
}
|
||||
|
||||
var _ core.ILogger = &SimpleLogger{}
|
||||
|
||||
// NewSimpleLogger use a special io.Writer as logger output
|
||||
func NewSimpleLogger(out io.Writer) *SimpleLogger {
|
||||
return &SimpleLogger{
|
||||
DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", DEFAULT_LOG_PREFIX), DEFAULT_LOG_FLAG),
|
||||
ERR: log.New(out, fmt.Sprintf("%s [error] ", DEFAULT_LOG_PREFIX), DEFAULT_LOG_FLAG),
|
||||
INFO: log.New(out, fmt.Sprintf("%s [info] ", DEFAULT_LOG_PREFIX), DEFAULT_LOG_FLAG),
|
||||
WARN: log.New(out, fmt.Sprintf("%s [warn] ", DEFAULT_LOG_PREFIX), DEFAULT_LOG_FLAG),
|
||||
level: DEFAULT_LOG_LEVEL,
|
||||
}
|
||||
}
|
||||
|
||||
// Error implement core.ILogger
|
||||
func (s *SimpleLogger) Error(v ...interface{}) {
|
||||
if s.level <= core.LOG_ERR {
|
||||
s.ERR.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf implement core.ILogger
|
||||
func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
|
||||
if s.level <= core.LOG_ERR {
|
||||
s.ERR.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Debug implement core.ILogger
|
||||
func (s *SimpleLogger) Debug(v ...interface{}) {
|
||||
if s.level <= core.LOG_DEBUG {
|
||||
s.DEBUG.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Debugf implement core.ILogger
|
||||
func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
|
||||
if s.level <= core.LOG_DEBUG {
|
||||
s.DEBUG.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Info implement core.ILogger
|
||||
func (s *SimpleLogger) Info(v ...interface{}) {
|
||||
if s.level <= core.LOG_INFO {
|
||||
s.INFO.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Infof implement core.ILogger
|
||||
func (s *SimpleLogger) Infof(format string, v ...interface{}) {
|
||||
if s.level <= core.LOG_INFO {
|
||||
s.INFO.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Warn implement core.ILogger
|
||||
func (s *SimpleLogger) Warn(v ...interface{}) {
|
||||
if s.level <= core.LOG_WARNING {
|
||||
s.WARN.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Warnf implement core.ILogger
|
||||
func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
|
||||
if s.level <= core.LOG_WARNING {
|
||||
s.WARN.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Level implement core.ILogger
|
||||
func (s *SimpleLogger) Level() core.LogLevel {
|
||||
return s.level
|
||||
}
|
||||
|
||||
// SetLevel implement core.ILogger
|
||||
func (s *SimpleLogger) SetLevel(l core.LogLevel) {
|
||||
s.level = l
|
||||
}
|
||||
|
||||
// ShowSQL implement core.ILogger
|
||||
func (s *SimpleLogger) ShowSQL(show ...bool) {
|
||||
if len(show) == 0 {
|
||||
s.showSQL = true
|
||||
return
|
||||
}
|
||||
s.showSQL = show[0]
|
||||
}
|
||||
|
||||
// IsShowSQL implement core.ILogger
|
||||
func (s *SimpleLogger) IsShowSQL() bool {
|
||||
return s.showSQL
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
// BeforeInsertProcessor executed before an object is initially persisted to the database
|
||||
type BeforeInsertProcessor interface {
|
||||
BeforeInsert()
|
||||
}
|
||||
|
||||
// BeforeUpdateProcessor executed before an object is updated
|
||||
type BeforeUpdateProcessor interface {
|
||||
BeforeUpdate()
|
||||
}
|
||||
|
||||
// BeforeDeleteProcessor executed before an object is deleted
|
||||
type BeforeDeleteProcessor interface {
|
||||
BeforeDelete()
|
||||
}
|
||||
|
||||
// BeforeSetProcessor executed before data set to the struct fields
|
||||
type BeforeSetProcessor interface {
|
||||
BeforeSet(string, Cell)
|
||||
}
|
||||
|
||||
// AfterSetProcessor executed after data set to the struct fields
|
||||
type AfterSetProcessor interface {
|
||||
AfterSet(string, Cell)
|
||||
}
|
||||
|
||||
// AfterInsertProcessor executed after an object is persisted to the database
|
||||
type AfterInsertProcessor interface {
|
||||
AfterInsert()
|
||||
}
|
||||
|
||||
// AfterUpdateProcessor executed after an object has been updated
|
||||
type AfterUpdateProcessor interface {
|
||||
AfterUpdate()
|
||||
}
|
||||
|
||||
// AfterDeleteProcessor executed after an object has been deleted
|
||||
type AfterDeleteProcessor interface {
|
||||
AfterDelete()
|
||||
}
|
||||
|
||||
// AfterLoadProcessor executed after an ojbect has been loaded from database
|
||||
type AfterLoadProcessor interface {
|
||||
AfterLoad()
|
||||
}
|
||||
|
||||
// AfterLoadSessionProcessor executed after an ojbect has been loaded from database with session parameter
|
||||
type AfterLoadSessionProcessor interface {
|
||||
AfterLoad(*Session)
|
||||
}
|
||||
|
||||
type executedProcessorFunc func(*Session, interface{}) error
|
||||
|
||||
type executedProcessor struct {
|
||||
fun executedProcessorFunc
|
||||
session *Session
|
||||
bean interface{}
|
||||
}
|
||||
|
||||
func (executor *executedProcessor) execute() error {
|
||||
return executor.fun(executor.session, executor.bean)
|
||||
}
|
||||
|
||||
func (session *Session) executeProcessors() error {
|
||||
processors := session.afterProcessors
|
||||
session.afterProcessors = make([]executedProcessor, 0)
|
||||
for _, processor := range processors {
|
||||
if err := processor.execute(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Rows rows wrapper a rows to
|
||||
type Rows struct {
|
||||
session *Session
|
||||
rows *core.Rows
|
||||
beanType reflect.Type
|
||||
lastError error
|
||||
}
|
||||
|
||||
func newRows(session *Session, bean interface{}) (*Rows, error) {
|
||||
rows := new(Rows)
|
||||
rows.session = session
|
||||
rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var err error
|
||||
|
||||
if err = rows.session.statement.setRefBean(bean); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
if rows.session.statement.RawSQL == "" {
|
||||
sqlStr, args, err = rows.session.statement.genGetSQL(bean)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
sqlStr = rows.session.statement.RawSQL
|
||||
args = rows.session.statement.RawParams
|
||||
}
|
||||
|
||||
rows.rows, err = rows.session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
rows.lastError = err
|
||||
rows.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
// Next move cursor to next record, return false if end has reached
|
||||
func (rows *Rows) Next() bool {
|
||||
if rows.lastError == nil && rows.rows != nil {
|
||||
hasNext := rows.rows.Next()
|
||||
if !hasNext {
|
||||
rows.lastError = sql.ErrNoRows
|
||||
}
|
||||
return hasNext
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
|
||||
func (rows *Rows) Err() error {
|
||||
return rows.lastError
|
||||
}
|
||||
|
||||
// Scan row record to bean properties
|
||||
func (rows *Rows) Scan(bean interface{}) error {
|
||||
if rows.lastError != nil {
|
||||
return rows.lastError
|
||||
}
|
||||
|
||||
if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
|
||||
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
|
||||
}
|
||||
|
||||
if err := rows.session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields, err := rows.rows.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanResults, err := rows.session.row2Slice(rows.rows, fields, bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataStruct := rValue(bean)
|
||||
_, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rows.session.executeProcessors()
|
||||
}
|
||||
|
||||
// Close session if session.IsAutoClose is true, and claimed any opened resources
|
||||
func (rows *Rows) Close() error {
|
||||
if rows.session.isAutoClose {
|
||||
defer rows.session.Close()
|
||||
}
|
||||
|
||||
if rows.rows != nil {
|
||||
return rows.rows.Close()
|
||||
}
|
||||
|
||||
return rows.lastError
|
||||
}
|
||||
@@ -1,808 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Session keep a pointer to sql.DB and provides all execution of all
|
||||
// kind of database operations.
|
||||
type Session struct {
|
||||
db *core.DB
|
||||
engine *Engine
|
||||
tx *core.Tx
|
||||
statement Statement
|
||||
isAutoCommit bool
|
||||
isCommitedOrRollbacked bool
|
||||
isAutoClose bool
|
||||
|
||||
// Automatically reset the statement after operations that execute a SQL
|
||||
// query such as Count(), Find(), Get(), ...
|
||||
autoResetStatement bool
|
||||
|
||||
// !nashtsai! storing these beans due to yet committed tx
|
||||
afterInsertBeans map[interface{}]*[]func(interface{})
|
||||
afterUpdateBeans map[interface{}]*[]func(interface{})
|
||||
afterDeleteBeans map[interface{}]*[]func(interface{})
|
||||
// --
|
||||
|
||||
beforeClosures []func(interface{})
|
||||
afterClosures []func(interface{})
|
||||
|
||||
afterProcessors []executedProcessor
|
||||
|
||||
prepareStmt bool
|
||||
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
|
||||
|
||||
// !evalphobia! stored the last executed query on this session
|
||||
lastSQL string
|
||||
lastSQLArgs []interface{}
|
||||
showSQL bool
|
||||
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// Init reset the session as the init status.
|
||||
func (session *Session) Init() {
|
||||
session.statement.Init()
|
||||
session.statement.Engine = session.engine
|
||||
session.showSQL = session.engine.showSQL
|
||||
session.isAutoCommit = true
|
||||
session.isCommitedOrRollbacked = false
|
||||
session.isAutoClose = false
|
||||
session.autoResetStatement = true
|
||||
session.prepareStmt = false
|
||||
|
||||
// !nashtsai! is lazy init better?
|
||||
session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
|
||||
session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0)
|
||||
session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
|
||||
session.beforeClosures = make([]func(interface{}), 0)
|
||||
session.afterClosures = make([]func(interface{}), 0)
|
||||
session.stmtCache = make(map[uint32]*core.Stmt)
|
||||
|
||||
session.afterProcessors = make([]executedProcessor, 0)
|
||||
|
||||
session.lastSQL = ""
|
||||
session.lastSQLArgs = []interface{}{}
|
||||
|
||||
session.ctx = session.engine.defaultContext
|
||||
}
|
||||
|
||||
// Close release the connection from pool
|
||||
func (session *Session) Close() {
|
||||
for _, v := range session.stmtCache {
|
||||
v.Close()
|
||||
}
|
||||
|
||||
if session.db != nil {
|
||||
// When Close be called, if session is a transaction and do not call
|
||||
// Commit or Rollback, then call Rollback.
|
||||
if session.tx != nil && !session.isCommitedOrRollbacked {
|
||||
session.Rollback()
|
||||
}
|
||||
session.tx = nil
|
||||
session.stmtCache = nil
|
||||
session.db = nil
|
||||
}
|
||||
}
|
||||
|
||||
// IsClosed returns if session is closed
|
||||
func (session *Session) IsClosed() bool {
|
||||
return session.db == nil
|
||||
}
|
||||
|
||||
func (session *Session) resetStatement() {
|
||||
if session.autoResetStatement {
|
||||
session.statement.Init()
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare set a flag to session that should be prepare statement before execute query
|
||||
func (session *Session) Prepare() *Session {
|
||||
session.prepareStmt = true
|
||||
return session
|
||||
}
|
||||
|
||||
// Before Apply before Processor, affected bean is passed to closure arg
|
||||
func (session *Session) Before(closures func(interface{})) *Session {
|
||||
if closures != nil {
|
||||
session.beforeClosures = append(session.beforeClosures, closures)
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// After Apply after Processor, affected bean is passed to closure arg
|
||||
func (session *Session) After(closures func(interface{})) *Session {
|
||||
if closures != nil {
|
||||
session.afterClosures = append(session.afterClosures, closures)
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// Table can input a string or pointer to struct for special a table to operate.
|
||||
func (session *Session) Table(tableNameOrBean interface{}) *Session {
|
||||
session.statement.Table(tableNameOrBean)
|
||||
return session
|
||||
}
|
||||
|
||||
// Alias set the table alias
|
||||
func (session *Session) Alias(alias string) *Session {
|
||||
session.statement.Alias(alias)
|
||||
return session
|
||||
}
|
||||
|
||||
// ForUpdate Set Read/Write locking for UPDATE
|
||||
func (session *Session) ForUpdate() *Session {
|
||||
session.statement.IsForUpdate = true
|
||||
return session
|
||||
}
|
||||
|
||||
// NoAutoCondition disable generate SQL condition from beans
|
||||
func (session *Session) NoAutoCondition(no ...bool) *Session {
|
||||
session.statement.NoAutoCondition(no...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Limit provide limit and offset query condition
|
||||
func (session *Session) Limit(limit int, start ...int) *Session {
|
||||
session.statement.Limit(limit, start...)
|
||||
return session
|
||||
}
|
||||
|
||||
// OrderBy provide order by query condition, the input parameter is the content
|
||||
// after order by on a sql statement.
|
||||
func (session *Session) OrderBy(order string) *Session {
|
||||
session.statement.OrderBy(order)
|
||||
return session
|
||||
}
|
||||
|
||||
// Desc provide desc order by query condition, the input parameters are columns.
|
||||
func (session *Session) Desc(colNames ...string) *Session {
|
||||
session.statement.Desc(colNames...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Asc provide asc order by query condition, the input parameters are columns.
|
||||
func (session *Session) Asc(colNames ...string) *Session {
|
||||
session.statement.Asc(colNames...)
|
||||
return session
|
||||
}
|
||||
|
||||
// StoreEngine is only avialble mysql dialect currently
|
||||
func (session *Session) StoreEngine(storeEngine string) *Session {
|
||||
session.statement.StoreEngine = storeEngine
|
||||
return session
|
||||
}
|
||||
|
||||
// Charset is only avialble mysql dialect currently
|
||||
func (session *Session) Charset(charset string) *Session {
|
||||
session.statement.Charset = charset
|
||||
return session
|
||||
}
|
||||
|
||||
// MustLogSQL means record SQL or not and don't follow engine's setting
|
||||
func (session *Session) MustLogSQL(log ...bool) *Session {
|
||||
if len(log) > 0 {
|
||||
session.showSQL = log[0]
|
||||
} else {
|
||||
session.showSQL = true
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// NoCache ask this session do not retrieve data from cache system and
|
||||
// get data from database directly.
|
||||
func (session *Session) NoCache() *Session {
|
||||
session.statement.UseCache = false
|
||||
return session
|
||||
}
|
||||
|
||||
// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
||||
func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
|
||||
session.statement.Join(joinOperator, tablename, condition, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// GroupBy Generate Group By statement
|
||||
func (session *Session) GroupBy(keys string) *Session {
|
||||
session.statement.GroupBy(keys)
|
||||
return session
|
||||
}
|
||||
|
||||
// Having Generate Having statement
|
||||
func (session *Session) Having(conditions string) *Session {
|
||||
session.statement.Having(conditions)
|
||||
return session
|
||||
}
|
||||
|
||||
// DB db return the wrapper of sql.DB
|
||||
func (session *Session) DB() *core.DB {
|
||||
if session.db == nil {
|
||||
session.db = session.engine.db
|
||||
session.stmtCache = make(map[uint32]*core.Stmt, 0)
|
||||
}
|
||||
return session.db
|
||||
}
|
||||
|
||||
func cleanupProcessorsClosures(slices *[]func(interface{})) {
|
||||
if len(*slices) > 0 {
|
||||
*slices = make([]func(interface{}), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) {
|
||||
crc := crc32.ChecksumIEEE([]byte(sqlStr))
|
||||
// TODO try hash(sqlStr+len(sqlStr))
|
||||
var has bool
|
||||
stmt, has = session.stmtCache[crc]
|
||||
if !has {
|
||||
stmt, err = db.PrepareContext(session.ctx, sqlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
session.stmtCache[crc] = stmt
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) {
|
||||
var col *core.Column
|
||||
if col = table.GetColumnIdx(key, idx); col == nil {
|
||||
return nil, ErrFieldIsNotExist{key, table.Name}
|
||||
}
|
||||
|
||||
fieldValue, err := col.ValueOfV(dataStruct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !fieldValue.IsValid() || !fieldValue.CanSet() {
|
||||
return nil, ErrFieldIsNotValid{key, table.Name}
|
||||
}
|
||||
|
||||
return fieldValue, nil
|
||||
}
|
||||
|
||||
// Cell cell is a result of one column field
|
||||
type Cell *interface{}
|
||||
|
||||
func (session *Session) rows2Beans(rows *core.Rows, fields []string,
|
||||
table *core.Table, newElemFunc func([]string) reflect.Value,
|
||||
sliceValueSetFunc func(*reflect.Value, core.PK) error) error {
|
||||
for rows.Next() {
|
||||
var newValue = newElemFunc(fields)
|
||||
bean := newValue.Interface()
|
||||
dataStruct := newValue.Elem()
|
||||
|
||||
// handle beforeClosures
|
||||
scanResults, err := session.row2Slice(rows, fields, bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.afterProcessors = append(session.afterProcessors, executedProcessor{
|
||||
fun: func(*Session, interface{}) error {
|
||||
return sliceValueSetFunc(&newValue, pk)
|
||||
},
|
||||
session: session,
|
||||
bean: bean,
|
||||
})
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func (session *Session) row2Slice(rows *core.Rows, fields []string, bean interface{}) ([]interface{}, error) {
|
||||
for _, closure := range session.beforeClosures {
|
||||
closure(bean)
|
||||
}
|
||||
|
||||
scanResults := make([]interface{}, len(fields))
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var cell interface{}
|
||||
scanResults[i] = &cell
|
||||
}
|
||||
if err := rows.Scan(scanResults...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
|
||||
for ii, key := range fields {
|
||||
b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
|
||||
}
|
||||
}
|
||||
return scanResults, nil
|
||||
}
|
||||
|
||||
func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) {
|
||||
defer func() {
|
||||
if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet {
|
||||
for ii, key := range fields {
|
||||
b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// handle afterClosures
|
||||
for _, closure := range session.afterClosures {
|
||||
session.afterProcessors = append(session.afterProcessors, executedProcessor{
|
||||
fun: func(sess *Session, bean interface{}) error {
|
||||
closure(bean)
|
||||
return nil
|
||||
},
|
||||
session: session,
|
||||
bean: bean,
|
||||
})
|
||||
}
|
||||
|
||||
if a, has := bean.(AfterLoadProcessor); has {
|
||||
session.afterProcessors = append(session.afterProcessors, executedProcessor{
|
||||
fun: func(sess *Session, bean interface{}) error {
|
||||
a.AfterLoad()
|
||||
return nil
|
||||
},
|
||||
session: session,
|
||||
bean: bean,
|
||||
})
|
||||
}
|
||||
|
||||
if a, has := bean.(AfterLoadSessionProcessor); has {
|
||||
session.afterProcessors = append(session.afterProcessors, executedProcessor{
|
||||
fun: func(sess *Session, bean interface{}) error {
|
||||
a.AfterLoad(sess)
|
||||
return nil
|
||||
},
|
||||
session: session,
|
||||
bean: bean,
|
||||
})
|
||||
}
|
||||
|
||||
var tempMap = make(map[string]int)
|
||||
var pk core.PK
|
||||
for ii, key := range fields {
|
||||
var idx int
|
||||
var ok bool
|
||||
var lKey = strings.ToLower(key)
|
||||
if idx, ok = tempMap[lKey]; !ok {
|
||||
idx = 0
|
||||
} else {
|
||||
idx = idx + 1
|
||||
}
|
||||
tempMap[lKey] = idx
|
||||
|
||||
fieldValue, err := session.getField(dataStruct, key, table, idx)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "is not valid") {
|
||||
session.engine.logger.Warn(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if fieldValue == nil {
|
||||
continue
|
||||
}
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
|
||||
|
||||
// if row is null then ignore
|
||||
if rawValue.Interface() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if fieldValue.CanAddr() {
|
||||
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
if err := structConvert.FromDB(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := fieldValue.Interface().(core.Conversion); ok {
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
|
||||
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
|
||||
}
|
||||
fieldValue.Interface().(core.Conversion).FromDB(data)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
rawValueType := reflect.TypeOf(rawValue.Interface())
|
||||
vv := reflect.ValueOf(rawValue.Interface())
|
||||
col := table.GetColumnIdx(key, idx)
|
||||
if col.IsPrimaryKey {
|
||||
pk = append(pk, rawValue.Interface())
|
||||
}
|
||||
fieldType := fieldValue.Type()
|
||||
hasAssigned := false
|
||||
|
||||
if col.SQLType.IsJson() {
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
} else if rawValueType.ConvertibleTo(core.BytesType) {
|
||||
bs = vv.Bytes()
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
|
||||
if len(bs) > 0 {
|
||||
if fieldType.Kind() == reflect.String {
|
||||
fieldValue.SetString(string(bs))
|
||||
continue
|
||||
}
|
||||
if fieldValue.CanAddr() {
|
||||
err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
x := reflect.New(fieldType)
|
||||
err := DefaultJSONHandler.Unmarshal(bs, x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
// TODO: reimplement this
|
||||
var bs []byte
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
bs = []byte(vv.String())
|
||||
} else if rawValueType.ConvertibleTo(core.BytesType) {
|
||||
bs = vv.Bytes()
|
||||
}
|
||||
|
||||
hasAssigned = true
|
||||
if len(bs) > 0 {
|
||||
if fieldValue.CanAddr() {
|
||||
err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
x := reflect.New(fieldType)
|
||||
err := DefaultJSONHandler.Unmarshal(bs, x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
case reflect.Slice, reflect.Array:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
switch rawValueType.Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
if fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
hasAssigned = true
|
||||
if col.SQLType.IsText() {
|
||||
x := reflect.New(fieldType)
|
||||
err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
} else {
|
||||
if fieldValue.Len() > 0 {
|
||||
for i := 0; i < fieldValue.Len(); i++ {
|
||||
if i < vv.Len() {
|
||||
fieldValue.Index(i).Set(vv.Index(i))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < vv.Len(); i++ {
|
||||
fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.String:
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
fieldValue.SetString(vv.String())
|
||||
}
|
||||
case reflect.Bool:
|
||||
if rawValueType.Kind() == reflect.Bool {
|
||||
hasAssigned = true
|
||||
fieldValue.SetBool(vv.Bool())
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetInt(vv.Int())
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetFloat(vv.Float())
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
switch rawValueType.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
hasAssigned = true
|
||||
fieldValue.SetUint(vv.Uint())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
hasAssigned = true
|
||||
fieldValue.SetUint(uint64(vv.Int()))
|
||||
}
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
dbTZ := session.engine.DatabaseTZ
|
||||
if col.TimeZone != nil {
|
||||
dbTZ = col.TimeZone
|
||||
}
|
||||
|
||||
if rawValueType == core.TimeType {
|
||||
hasAssigned = true
|
||||
|
||||
t := vv.Convert(core.TimeType).Interface().(time.Time)
|
||||
|
||||
z, _ := t.Zone()
|
||||
// set new location if database don't save timezone or give an incorrect timezone
|
||||
if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
|
||||
session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
|
||||
t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
|
||||
}
|
||||
|
||||
t = t.In(session.engine.TZLocation)
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
|
||||
rawValueType == core.Int32Type {
|
||||
hasAssigned = true
|
||||
|
||||
t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
} else {
|
||||
if d, ok := vv.Interface().([]uint8); ok {
|
||||
hasAssigned = true
|
||||
t, err := session.byte2Time(col, d)
|
||||
if err != nil {
|
||||
session.engine.logger.Error("byte2Time error:", err.Error())
|
||||
hasAssigned = false
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
}
|
||||
} else if d, ok := vv.Interface().(string); ok {
|
||||
hasAssigned = true
|
||||
t, err := session.str2Time(col, d)
|
||||
if err != nil {
|
||||
session.engine.logger.Error("byte2Time error:", err.Error())
|
||||
hasAssigned = false
|
||||
} else {
|
||||
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
|
||||
}
|
||||
}
|
||||
} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
|
||||
// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
|
||||
hasAssigned = true
|
||||
if err := nulVal.Scan(vv.Interface()); err != nil {
|
||||
session.engine.logger.Error("sql.Sanner error:", err.Error())
|
||||
hasAssigned = false
|
||||
}
|
||||
} else if col.SQLType.IsJson() {
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
} else if rawValueType.Kind() == reflect.Slice {
|
||||
hasAssigned = true
|
||||
x := reflect.New(fieldType)
|
||||
if len(vv.Bytes()) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
// !nashtsai! TODO merge duplicated codes above
|
||||
switch fieldType {
|
||||
// following types case matching ptr's native type, therefore assign ptr directly
|
||||
case core.PtrStringType:
|
||||
if rawValueType.Kind() == reflect.String {
|
||||
x := vv.String()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrBoolType:
|
||||
if rawValueType.Kind() == reflect.Bool {
|
||||
x := vv.Bool()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrTimeType:
|
||||
if rawValueType == core.PtrTimeType {
|
||||
hasAssigned = true
|
||||
var x = rawValue.Interface().(time.Time)
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrFloat64Type:
|
||||
if rawValueType.Kind() == reflect.Float64 {
|
||||
x := vv.Float()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUint64Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint64(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt64Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
x := vv.Int()
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrFloat32Type:
|
||||
if rawValueType.Kind() == reflect.Float64 {
|
||||
var x = float32(vv.Float())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrIntType:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt32Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int32(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt8Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int8(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrInt16Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = int16(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUintType:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.PtrUint32Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint32(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Uint8Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint8(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Uint16Type:
|
||||
if rawValueType.Kind() == reflect.Int64 {
|
||||
var x = uint16(vv.Int())
|
||||
hasAssigned = true
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
case core.Complex64Type:
|
||||
var x complex64
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
hasAssigned = true
|
||||
case core.Complex128Type:
|
||||
var x complex128
|
||||
if len([]byte(vv.String())) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
}
|
||||
hasAssigned = true
|
||||
} // switch fieldType
|
||||
} // switch fieldType.Kind()
|
||||
|
||||
// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
|
||||
if !hasAssigned {
|
||||
data, err := value2Bytes(&rawValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = session.bytes2Value(col, fieldValue, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// saveLastSQL stores executed query information
|
||||
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
|
||||
session.lastSQL = sql
|
||||
session.lastSQLArgs = args
|
||||
session.logSQL(sql, args...)
|
||||
}
|
||||
|
||||
func (session *Session) logSQL(sqlStr string, sqlArgs ...interface{}) {
|
||||
if session.showSQL && !session.engine.showExecTime {
|
||||
if len(sqlArgs) > 0 {
|
||||
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, sqlArgs)
|
||||
} else {
|
||||
session.engine.logger.Infof("[SQL] %v", sqlStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LastSQL returns last query information
|
||||
func (session *Session) LastSQL() (string, []interface{}) {
|
||||
return session.lastSQL, session.lastSQLArgs
|
||||
}
|
||||
|
||||
// Unscoped always disable struct tag "deleted"
|
||||
func (session *Session) Unscoped() *Session {
|
||||
session.statement.Unscoped()
|
||||
return session
|
||||
}
|
||||
|
||||
func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
|
||||
switch fieldValue.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
fieldValue.SetInt(fieldValue.Int() + 1)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
fieldValue.SetUint(fieldValue.Uint() + 1)
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func setColumnInt(bean interface{}, col *core.Column, t int64) {
|
||||
v, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v.CanSet() {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int, reflect.Int64, reflect.Int32:
|
||||
v.SetInt(t)
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32:
|
||||
v.SetUint(uint64(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
|
||||
v, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v.CanSet() {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Struct:
|
||||
v.Set(reflect.ValueOf(t).Convert(v.Type()))
|
||||
case reflect.Int, reflect.Int64, reflect.Int32:
|
||||
v.SetInt(t.Unix())
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32:
|
||||
v.SetUint(uint64(t.Unix()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
|
||||
if len(m) == 0 {
|
||||
return false, false
|
||||
}
|
||||
|
||||
n := len(col.Name)
|
||||
|
||||
for mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, col.Name) {
|
||||
return m[mk], true
|
||||
}
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
||||
|
||||
func col2NewCols(columns ...string) []string {
|
||||
newColumns := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
col = strings.Replace(col, "`", "", -1)
|
||||
col = strings.Replace(col, `"`, "", -1)
|
||||
ccols := strings.Split(col, ",")
|
||||
for _, c := range ccols {
|
||||
newColumns = append(newColumns, strings.TrimSpace(c))
|
||||
}
|
||||
}
|
||||
return newColumns
|
||||
}
|
||||
|
||||
// Select provides some columns to special
|
||||
func (session *Session) Select(str string) *Session {
|
||||
session.statement.Select(str)
|
||||
return session
|
||||
}
|
||||
|
||||
// Cols provides some columns to special
|
||||
func (session *Session) Cols(columns ...string) *Session {
|
||||
session.statement.Cols(columns...)
|
||||
return session
|
||||
}
|
||||
|
||||
// AllCols ask all columns
|
||||
func (session *Session) AllCols() *Session {
|
||||
session.statement.AllCols()
|
||||
return session
|
||||
}
|
||||
|
||||
// MustCols specify some columns must use even if they are empty
|
||||
func (session *Session) MustCols(columns ...string) *Session {
|
||||
session.statement.MustCols(columns...)
|
||||
return session
|
||||
}
|
||||
|
||||
// UseBool automatically retrieve condition according struct, but
|
||||
// if struct has bool field, it will ignore them. So use UseBool
|
||||
// to tell system to do not ignore them.
|
||||
// If no parameters, it will use all the bool field of struct, or
|
||||
// it will use parameters's columns
|
||||
func (session *Session) UseBool(columns ...string) *Session {
|
||||
session.statement.UseBool(columns...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Distinct use for distinct columns. Caution: when you are using cache,
|
||||
// distinct will not be cached because cache system need id,
|
||||
// but distinct will not provide id
|
||||
func (session *Session) Distinct(columns ...string) *Session {
|
||||
session.statement.Distinct(columns...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Nullable Set null when column is zero-value and nullable for update
|
||||
func (session *Session) Nullable(columns ...string) *Session {
|
||||
session.statement.Nullable(columns...)
|
||||
return session
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import "xorm.io/builder"
|
||||
|
||||
// Sql provides raw sql input parameter. When you have a complex SQL statement
|
||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
|
||||
//
|
||||
// Deprecated: use SQL instead.
|
||||
func (session *Session) Sql(query string, args ...interface{}) *Session {
|
||||
return session.SQL(query, args...)
|
||||
}
|
||||
|
||||
// SQL provides raw sql input parameter. When you have a complex SQL statement
|
||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
|
||||
func (session *Session) SQL(query interface{}, args ...interface{}) *Session {
|
||||
session.statement.SQL(query, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Where provides custom query condition.
|
||||
func (session *Session) Where(query interface{}, args ...interface{}) *Session {
|
||||
session.statement.Where(query, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// And provides custom query condition.
|
||||
func (session *Session) And(query interface{}, args ...interface{}) *Session {
|
||||
session.statement.And(query, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Or provides custom query condition.
|
||||
func (session *Session) Or(query interface{}, args ...interface{}) *Session {
|
||||
session.statement.Or(query, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Id provides converting id as a query condition
|
||||
//
|
||||
// Deprecated: use ID instead
|
||||
func (session *Session) Id(id interface{}) *Session {
|
||||
return session.ID(id)
|
||||
}
|
||||
|
||||
// ID provides converting id as a query condition
|
||||
func (session *Session) ID(id interface{}) *Session {
|
||||
session.statement.ID(id)
|
||||
return session
|
||||
}
|
||||
|
||||
// In provides a query string like "id in (1, 2, 3)"
|
||||
func (session *Session) In(column string, args ...interface{}) *Session {
|
||||
session.statement.In(column, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// NotIn provides a query string like "id in (1, 2, 3)"
|
||||
func (session *Session) NotIn(column string, args ...interface{}) *Session {
|
||||
session.statement.NotIn(column, args...)
|
||||
return session
|
||||
}
|
||||
|
||||
// Conds returns session query conditions except auto bean conditions
|
||||
func (session *Session) Conds() builder.Cond {
|
||||
return session.statement.cond
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import "context"
|
||||
|
||||
// Context sets the context on this session
|
||||
func (session *Session) Context(ctx context.Context) *Session {
|
||||
session.ctx = ctx
|
||||
return session
|
||||
}
|
||||
|
||||
// PingContext test if database is ok
|
||||
func (session *Session) PingContext(ctx context.Context) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
|
||||
return session.DB().PingContext(ctx)
|
||||
}
|
||||
@@ -1,606 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
const (
|
||||
zeroTime0 = "0000-00-00 00:00:00"
|
||||
zeroTime1 = "0001-01-01 00:00:00"
|
||||
)
|
||||
|
||||
func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) {
|
||||
sdata := strings.TrimSpace(data)
|
||||
var x time.Time
|
||||
var err error
|
||||
|
||||
var parseLoc = session.engine.DatabaseTZ
|
||||
if col.TimeZone != nil {
|
||||
parseLoc = col.TimeZone
|
||||
}
|
||||
|
||||
if sdata == zeroTime0 || sdata == zeroTime1 {
|
||||
} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
|
||||
// time stamp
|
||||
sd, err := strconv.ParseInt(sdata, 10, 64)
|
||||
if err == nil {
|
||||
x = time.Unix(sd, 0)
|
||||
//session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else {
|
||||
//session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
}
|
||||
} else if len(sdata) > 19 && strings.Contains(sdata, "-") {
|
||||
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
|
||||
session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
if err != nil {
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
|
||||
//session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
}
|
||||
if err != nil {
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
|
||||
//session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
}
|
||||
} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
|
||||
//session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
||||
x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
|
||||
//session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else if col.SQLType.Name == core.Time {
|
||||
if strings.Contains(sdata, " ") {
|
||||
ssd := strings.Split(sdata, " ")
|
||||
sdata = ssd[1]
|
||||
}
|
||||
|
||||
sdata = strings.TrimSpace(sdata)
|
||||
if session.engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
|
||||
sdata = sdata[len(sdata)-8:]
|
||||
}
|
||||
|
||||
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
||||
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
|
||||
//session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
|
||||
} else {
|
||||
outErr = fmt.Errorf("unsupported time format %v", sdata)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
|
||||
return
|
||||
}
|
||||
outTime = x.In(session.engine.TZLocation)
|
||||
return
|
||||
}
|
||||
|
||||
func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
|
||||
return session.str2Time(col, string(data))
|
||||
}
|
||||
|
||||
var (
|
||||
nullFloatType = reflect.TypeOf(sql.NullFloat64{})
|
||||
)
|
||||
|
||||
// convert a db data([]byte) to a field value
|
||||
func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
|
||||
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
|
||||
return structConvert.FromDB(data)
|
||||
}
|
||||
|
||||
if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
|
||||
return structConvert.FromDB(data)
|
||||
}
|
||||
|
||||
var v interface{}
|
||||
key := col.Name
|
||||
fieldType := fieldValue.Type()
|
||||
|
||||
switch fieldType.Kind() {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
x := reflect.New(fieldType)
|
||||
if len(data) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal(data, x.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
case reflect.Slice, reflect.Array, reflect.Map:
|
||||
v = data
|
||||
t := fieldType.Elem()
|
||||
k := t.Kind()
|
||||
if col.SQLType.IsText() {
|
||||
x := reflect.New(fieldType)
|
||||
if len(data) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal(data, x.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
} else if col.SQLType.IsBlob() {
|
||||
if k == reflect.Uint8 {
|
||||
fieldValue.Set(reflect.ValueOf(v))
|
||||
} else {
|
||||
x := reflect.New(fieldType)
|
||||
if len(data) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal(data, x.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(x.Elem())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ErrUnSupportedType
|
||||
}
|
||||
case reflect.String:
|
||||
fieldValue.SetString(string(data))
|
||||
case reflect.Bool:
|
||||
v, err := asBool(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as bool: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(v))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
sdata := string(data)
|
||||
var x int64
|
||||
var err error
|
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit &&
|
||||
session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
|
||||
if len(data) == 1 {
|
||||
x = int64(data[0])
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
} else if strings.HasPrefix(sdata, "0x") {
|
||||
x, err = strconv.ParseInt(sdata, 16, 64)
|
||||
} else if strings.HasPrefix(sdata, "0") {
|
||||
x, err = strconv.ParseInt(sdata, 8, 64)
|
||||
} else if strings.EqualFold(sdata, "true") {
|
||||
x = 1
|
||||
} else if strings.EqualFold(sdata, "false") {
|
||||
x = 0
|
||||
} else {
|
||||
x, err = strconv.ParseInt(sdata, 10, 64)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.SetInt(x)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
x, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as float64: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.SetFloat(x)
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
x, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.SetUint(x)
|
||||
//Currently only support Time type
|
||||
case reflect.Struct:
|
||||
// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
|
||||
if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
|
||||
if err := nulVal.Scan(data); err != nil {
|
||||
return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
|
||||
}
|
||||
} else {
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
x, err := session.byte2Time(col, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = x
|
||||
fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
// !nashtsai! TODO merge duplicated codes above
|
||||
//typeStr := fieldType.String()
|
||||
switch fieldType.Elem().Kind() {
|
||||
// case "*string":
|
||||
case core.StringType.Kind():
|
||||
x := string(data)
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*bool":
|
||||
case core.BoolType.Kind():
|
||||
d := string(data)
|
||||
v, err := strconv.ParseBool(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as bool: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
|
||||
// case "*complex64":
|
||||
case core.Complex64Type.Kind():
|
||||
var x complex64
|
||||
if len(data) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal(data, &x)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
}
|
||||
// case "*complex128":
|
||||
case core.Complex128Type.Kind():
|
||||
var x complex128
|
||||
if len(data) > 0 {
|
||||
err := DefaultJSONHandler.Unmarshal(data, &x)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return err
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
}
|
||||
// case "*float64":
|
||||
case core.Float64Type.Kind():
|
||||
x, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as float64: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*float32":
|
||||
case core.Float32Type.Kind():
|
||||
var x float32
|
||||
x1, err := strconv.ParseFloat(string(data), 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as float32: %s", key, err.Error())
|
||||
}
|
||||
x = float32(x1)
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*uint64":
|
||||
case core.Uint64Type.Kind():
|
||||
var x uint64
|
||||
x, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*uint":
|
||||
case core.UintType.Kind():
|
||||
var x uint
|
||||
x1, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
x = uint(x1)
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*uint32":
|
||||
case core.Uint32Type.Kind():
|
||||
var x uint32
|
||||
x1, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
x = uint32(x1)
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*uint8":
|
||||
case core.Uint8Type.Kind():
|
||||
var x uint8
|
||||
x1, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
x = uint8(x1)
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*uint16":
|
||||
case core.Uint16Type.Kind():
|
||||
var x uint16
|
||||
x1, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
x = uint16(x1)
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*int64":
|
||||
case core.Int64Type.Kind():
|
||||
sdata := string(data)
|
||||
var x int64
|
||||
var err error
|
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit &&
|
||||
strings.Contains(session.engine.DriverName(), "mysql") {
|
||||
if len(data) == 1 {
|
||||
x = int64(data[0])
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
} else if strings.HasPrefix(sdata, "0x") {
|
||||
x, err = strconv.ParseInt(sdata, 16, 64)
|
||||
} else if strings.HasPrefix(sdata, "0") {
|
||||
x, err = strconv.ParseInt(sdata, 8, 64)
|
||||
} else {
|
||||
x, err = strconv.ParseInt(sdata, 10, 64)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*int":
|
||||
case core.IntType.Kind():
|
||||
sdata := string(data)
|
||||
var x int
|
||||
var x1 int64
|
||||
var err error
|
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit &&
|
||||
strings.Contains(session.engine.DriverName(), "mysql") {
|
||||
if len(data) == 1 {
|
||||
x = int(data[0])
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
} else if strings.HasPrefix(sdata, "0x") {
|
||||
x1, err = strconv.ParseInt(sdata, 16, 64)
|
||||
x = int(x1)
|
||||
} else if strings.HasPrefix(sdata, "0") {
|
||||
x1, err = strconv.ParseInt(sdata, 8, 64)
|
||||
x = int(x1)
|
||||
} else {
|
||||
x1, err = strconv.ParseInt(sdata, 10, 64)
|
||||
x = int(x1)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*int32":
|
||||
case core.Int32Type.Kind():
|
||||
sdata := string(data)
|
||||
var x int32
|
||||
var x1 int64
|
||||
var err error
|
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit &&
|
||||
session.engine.dialect.DBType() == core.MYSQL {
|
||||
if len(data) == 1 {
|
||||
x = int32(data[0])
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
} else if strings.HasPrefix(sdata, "0x") {
|
||||
x1, err = strconv.ParseInt(sdata, 16, 64)
|
||||
x = int32(x1)
|
||||
} else if strings.HasPrefix(sdata, "0") {
|
||||
x1, err = strconv.ParseInt(sdata, 8, 64)
|
||||
x = int32(x1)
|
||||
} else {
|
||||
x1, err = strconv.ParseInt(sdata, 10, 64)
|
||||
x = int32(x1)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*int8":
|
||||
case core.Int8Type.Kind():
|
||||
sdata := string(data)
|
||||
var x int8
|
||||
var x1 int64
|
||||
var err error
|
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit &&
|
||||
strings.Contains(session.engine.DriverName(), "mysql") {
|
||||
if len(data) == 1 {
|
||||
x = int8(data[0])
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
} else if strings.HasPrefix(sdata, "0x") {
|
||||
x1, err = strconv.ParseInt(sdata, 16, 64)
|
||||
x = int8(x1)
|
||||
} else if strings.HasPrefix(sdata, "0") {
|
||||
x1, err = strconv.ParseInt(sdata, 8, 64)
|
||||
x = int8(x1)
|
||||
} else {
|
||||
x1, err = strconv.ParseInt(sdata, 10, 64)
|
||||
x = int8(x1)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*int16":
|
||||
case core.Int16Type.Kind():
|
||||
sdata := string(data)
|
||||
var x int16
|
||||
var x1 int64
|
||||
var err error
|
||||
// for mysql, when use bit, it returned \x01
|
||||
if col.SQLType.Name == core.Bit &&
|
||||
strings.Contains(session.engine.DriverName(), "mysql") {
|
||||
if len(data) == 1 {
|
||||
x = int16(data[0])
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
} else if strings.HasPrefix(sdata, "0x") {
|
||||
x1, err = strconv.ParseInt(sdata, 16, 64)
|
||||
x = int16(x1)
|
||||
} else if strings.HasPrefix(sdata, "0") {
|
||||
x1, err = strconv.ParseInt(sdata, 8, 64)
|
||||
x = int16(x1)
|
||||
} else {
|
||||
x1, err = strconv.ParseInt(sdata, 10, 64)
|
||||
x = int16(x1)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("arg %v as int: %s", key, err.Error())
|
||||
}
|
||||
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
|
||||
// case "*SomeStruct":
|
||||
case reflect.Struct:
|
||||
switch fieldType {
|
||||
// case "*.time.Time":
|
||||
case core.PtrTimeType:
|
||||
x, err := session.byte2Time(col, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = x
|
||||
fieldValue.Set(reflect.ValueOf(&x))
|
||||
default:
|
||||
return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// convert a field value of a struct to interface for put into db
|
||||
func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
|
||||
if fieldValue.CanAddr() {
|
||||
if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
|
||||
data, err := fieldConvert.ToDB()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if col.SQLType.IsBlob() {
|
||||
return data, nil
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
}
|
||||
|
||||
if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
|
||||
data, err := fieldConvert.ToDB()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if col.SQLType.IsBlob() {
|
||||
return data, nil
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
fieldType := fieldValue.Type()
|
||||
k := fieldType.Kind()
|
||||
if k == reflect.Ptr {
|
||||
if fieldValue.IsNil() {
|
||||
return nil, nil
|
||||
} else if !fieldValue.IsValid() {
|
||||
session.engine.logger.Warn("the field[", col.FieldName, "] is invalid")
|
||||
return nil, nil
|
||||
} else {
|
||||
// !nashtsai! deference pointer type to instance type
|
||||
fieldValue = fieldValue.Elem()
|
||||
fieldType = fieldValue.Type()
|
||||
k = fieldType.Kind()
|
||||
}
|
||||
}
|
||||
|
||||
switch k {
|
||||
case reflect.Bool:
|
||||
return fieldValue.Bool(), nil
|
||||
case reflect.String:
|
||||
return fieldValue.String(), nil
|
||||
case reflect.Struct:
|
||||
if fieldType.ConvertibleTo(core.TimeType) {
|
||||
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
|
||||
tf := session.engine.formatColTime(col, t)
|
||||
return tf, nil
|
||||
} else if fieldType.ConvertibleTo(nullFloatType) {
|
||||
t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
|
||||
if !t.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return t.Float64, nil
|
||||
}
|
||||
|
||||
if !col.SQLType.IsJson() {
|
||||
// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
|
||||
if v, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||
return v.Value()
|
||||
}
|
||||
|
||||
fieldTable, err := session.engine.autoMapType(fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(fieldTable.PrimaryKeys) == 1 {
|
||||
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
|
||||
return pkField.Interface(), nil
|
||||
}
|
||||
return 0, fmt.Errorf("no primary key for col %v", col.Name)
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
return string(bytes), nil
|
||||
} else if col.SQLType.IsBlob() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported type %v", fieldValue.Type())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
return string(bytes), nil
|
||||
case reflect.Array, reflect.Slice, reflect.Map:
|
||||
if !fieldValue.IsValid() {
|
||||
return fieldValue.Interface(), nil
|
||||
}
|
||||
|
||||
if col.SQLType.IsText() {
|
||||
bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
return string(bytes), nil
|
||||
} else if col.SQLType.IsBlob() {
|
||||
var bytes []byte
|
||||
var err error
|
||||
if (k == reflect.Slice) &&
|
||||
(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
|
||||
bytes = fieldValue.Bytes()
|
||||
} else {
|
||||
bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
return nil, ErrUnSupportedType
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
return int64(fieldValue.Uint()), nil
|
||||
default:
|
||||
return fieldValue.Interface(), nil
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Delete records, bean's non-empty fields are conditions
|
||||
func (session *Session) Delete(bean interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if session.statement.lastError != nil {
|
||||
return 0, session.statement.lastError
|
||||
}
|
||||
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// handle before delete processors
|
||||
for _, closure := range session.beforeClosures {
|
||||
closure(bean)
|
||||
}
|
||||
cleanupProcessorsClosures(&session.beforeClosures)
|
||||
|
||||
if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
|
||||
processor.BeforeDelete()
|
||||
}
|
||||
|
||||
condSQL, condArgs, err := session.statement.genConds(bean)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
pLimitN := session.statement.LimitN
|
||||
if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) {
|
||||
return 0, ErrNeedDeletedCond
|
||||
}
|
||||
|
||||
var tableNameNoQuote = session.statement.TableName()
|
||||
var tableName = session.engine.Quote(tableNameNoQuote)
|
||||
var table = session.statement.RefTable
|
||||
var deleteSQL string
|
||||
if len(condSQL) > 0 {
|
||||
deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
|
||||
} else {
|
||||
deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
|
||||
}
|
||||
|
||||
var orderSQL string
|
||||
if len(session.statement.OrderStr) > 0 {
|
||||
orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
|
||||
}
|
||||
if pLimitN != nil && *pLimitN > 0 {
|
||||
limitNValue := *pLimitN
|
||||
orderSQL += fmt.Sprintf(" LIMIT %d", limitNValue)
|
||||
}
|
||||
|
||||
if len(orderSQL) > 0 {
|
||||
switch session.engine.dialect.DBType() {
|
||||
case core.POSTGRES:
|
||||
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
|
||||
if len(condSQL) > 0 {
|
||||
deleteSQL += " AND " + inSQL
|
||||
} else {
|
||||
deleteSQL += " WHERE " + inSQL
|
||||
}
|
||||
case core.SQLITE:
|
||||
inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
|
||||
if len(condSQL) > 0 {
|
||||
deleteSQL += " AND " + inSQL
|
||||
} else {
|
||||
deleteSQL += " WHERE " + inSQL
|
||||
}
|
||||
default:
|
||||
deleteSQL += orderSQL
|
||||
}
|
||||
}
|
||||
|
||||
var realSQL string
|
||||
|
||||
if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
|
||||
realSQL = deleteSQL
|
||||
} else {
|
||||
deletedColumn := table.DeletedColumn()
|
||||
realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
|
||||
session.engine.Quote(session.statement.TableName()),
|
||||
session.engine.Quote(deletedColumn.Name),
|
||||
condSQL)
|
||||
|
||||
if len(orderSQL) > 0 {
|
||||
switch session.engine.dialect.DBType() {
|
||||
case core.POSTGRES:
|
||||
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
|
||||
if len(condSQL) > 0 {
|
||||
realSQL += " AND " + inSQL
|
||||
} else {
|
||||
realSQL += " WHERE " + inSQL
|
||||
}
|
||||
case core.SQLITE:
|
||||
inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
|
||||
if len(condSQL) > 0 {
|
||||
realSQL += " AND " + inSQL
|
||||
} else {
|
||||
realSQL += " WHERE " + inSQL
|
||||
}
|
||||
default:
|
||||
realSQL += orderSQL
|
||||
}
|
||||
}
|
||||
|
||||
// !oinume! Insert nowTime to the head of session.statement.Params
|
||||
condArgs = append(condArgs, "")
|
||||
paramsLen := len(condArgs)
|
||||
copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
|
||||
|
||||
val, t := session.engine.nowTime(deletedColumn)
|
||||
condArgs[0] = val
|
||||
|
||||
var colName = deletedColumn.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
}
|
||||
session.statement.RefTable = table
|
||||
res, err := session.exec(realSQL, condArgs...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// handle after delete processors
|
||||
if session.isAutoCommit {
|
||||
for _, closure := range session.afterClosures {
|
||||
closure(bean)
|
||||
}
|
||||
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
|
||||
processor.AfterDelete()
|
||||
}
|
||||
} else {
|
||||
lenAfterClosures := len(session.afterClosures)
|
||||
if lenAfterClosures > 0 {
|
||||
if value, has := session.afterDeleteBeans[bean]; has && value != nil {
|
||||
*value = append(*value, session.afterClosures...)
|
||||
} else {
|
||||
afterClosures := make([]func(interface{}), lenAfterClosures)
|
||||
copy(afterClosures, session.afterClosures)
|
||||
session.afterDeleteBeans[bean] = &afterClosures
|
||||
}
|
||||
} else {
|
||||
if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
|
||||
session.afterDeleteBeans[bean] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanupProcessorsClosures(&session.afterClosures)
|
||||
|
||||
return res.RowsAffected()
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Exist returns true if the record exist otherwise return false
|
||||
func (session *Session) Exist(bean ...interface{}) (bool, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if session.statement.lastError != nil {
|
||||
return false, session.statement.lastError
|
||||
}
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var joinStr string
|
||||
var err error
|
||||
if session.statement.RawSQL == "" {
|
||||
if len(bean) == 0 {
|
||||
tableName := session.statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return false, ErrTableNotFound
|
||||
}
|
||||
|
||||
tableName = session.statement.Engine.Quote(tableName)
|
||||
if len(session.statement.JoinStr) > 0 {
|
||||
joinStr = session.statement.JoinStr
|
||||
}
|
||||
|
||||
if session.statement.cond.IsValid() {
|
||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if session.engine.dialect.DBType() == core.ORACLE {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) %s AND ROWNUM=1", tableName, joinStr, condSQL)
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s %s WHERE %s LIMIT 1", tableName, joinStr, condSQL)
|
||||
}
|
||||
args = condArgs
|
||||
} else {
|
||||
if session.engine.dialect.DBType() == core.ORACLE {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s %s WHERE ROWNUM=1", tableName, joinStr)
|
||||
} else {
|
||||
sqlStr = fmt.Sprintf("SELECT * FROM %s %s LIMIT 1", tableName, joinStr)
|
||||
}
|
||||
args = []interface{}{}
|
||||
}
|
||||
} else {
|
||||
beanValue := reflect.ValueOf(bean[0])
|
||||
if beanValue.Kind() != reflect.Ptr {
|
||||
return false, errors.New("needs a pointer")
|
||||
}
|
||||
|
||||
if beanValue.Elem().Kind() == reflect.Struct {
|
||||
if err := session.statement.setRefBean(bean[0]); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return false, ErrTableNotFound
|
||||
}
|
||||
session.statement.Limit(1)
|
||||
sqlStr, args, err = session.statement.genGetSQL(bean[0])
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sqlStr = session.statement.RawSQL
|
||||
args = session.statement.RawParams
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
return true, nil
|
||||
}
|
||||
return false, rows.Err()
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
const (
|
||||
tpStruct = iota
|
||||
tpNonStruct
|
||||
)
|
||||
|
||||
// Find retrieve records from table, condiBeans's non-empty fields
|
||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
|
||||
// map[int64]*Struct
|
||||
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
return session.find(rowsSlicePtr, condiBean...)
|
||||
}
|
||||
|
||||
// FindAndCount find the results and also return the counts
|
||||
func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
session.autoResetStatement = false
|
||||
err := session.find(rowsSlicePtr, condiBean...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
|
||||
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
|
||||
return 0, errors.New("needs a pointer to a slice or a map")
|
||||
}
|
||||
|
||||
sliceElementType := sliceValue.Type().Elem()
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
sliceElementType = sliceElementType.Elem()
|
||||
}
|
||||
session.autoResetStatement = true
|
||||
|
||||
if session.statement.selectStr != "" {
|
||||
session.statement.selectStr = ""
|
||||
}
|
||||
if session.statement.OrderStr != "" {
|
||||
session.statement.OrderStr = ""
|
||||
}
|
||||
|
||||
return session.Count(reflect.New(sliceElementType).Interface())
|
||||
}
|
||||
|
||||
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
|
||||
defer session.resetStatement()
|
||||
|
||||
if session.statement.lastError != nil {
|
||||
return session.statement.lastError
|
||||
}
|
||||
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
|
||||
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
|
||||
return errors.New("needs a pointer to a slice or a map")
|
||||
}
|
||||
|
||||
sliceElementType := sliceValue.Type().Elem()
|
||||
|
||||
var tp = tpStruct
|
||||
if session.statement.RefTable == nil {
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
if sliceElementType.Elem().Kind() == reflect.Struct {
|
||||
pv := reflect.New(sliceElementType.Elem())
|
||||
if err := session.statement.setRefValue(pv); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
tp = tpNonStruct
|
||||
}
|
||||
} else if sliceElementType.Kind() == reflect.Struct {
|
||||
pv := reflect.New(sliceElementType)
|
||||
if err := session.statement.setRefValue(pv); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
tp = tpNonStruct
|
||||
}
|
||||
}
|
||||
|
||||
var table = session.statement.RefTable
|
||||
|
||||
var addedTableName = (len(session.statement.JoinStr) > 0)
|
||||
var autoCond builder.Cond
|
||||
if tp == tpStruct {
|
||||
if !session.statement.noAutoCondition && len(condiBean) > 0 {
|
||||
var err error
|
||||
autoCond, err = session.statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
|
||||
// See https://gitea.com/xorm/xorm/issues/179
|
||||
if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
|
||||
var colName = session.engine.Quote(col.Name)
|
||||
if addedTableName {
|
||||
var nm = session.statement.TableName()
|
||||
if len(session.statement.TableAlias) > 0 {
|
||||
nm = session.statement.TableAlias
|
||||
}
|
||||
colName = session.engine.Quote(nm) + "." + colName
|
||||
}
|
||||
|
||||
autoCond = session.engine.CondDeleted(col)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
// var err error
|
||||
if session.statement.RawSQL == "" {
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return ErrTableNotFound
|
||||
}
|
||||
|
||||
var columnStr = session.statement.ColumnStr
|
||||
if len(session.statement.selectStr) > 0 {
|
||||
columnStr = session.statement.selectStr
|
||||
} else {
|
||||
if session.statement.JoinStr == "" {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = session.statement.genColumnStr()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
if columnStr == "" {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
|
||||
session.statement.cond = session.statement.cond.And(autoCond)
|
||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
args = append(session.statement.joinArgs, condArgs...)
|
||||
sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// for mssql and use limit
|
||||
qs := strings.Count(sqlStr, "?")
|
||||
if len(args)*2 == qs {
|
||||
args = append(args, args...)
|
||||
}
|
||||
} else {
|
||||
sqlStr = session.statement.RawSQL
|
||||
args = session.statement.RawParams
|
||||
}
|
||||
|
||||
return session.noCacheFind(table, sliceValue, sqlStr, args...)
|
||||
}
|
||||
|
||||
func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var newElemFunc func(fields []string) reflect.Value
|
||||
elemType := containerValue.Type().Elem()
|
||||
var isPointer bool
|
||||
if elemType.Kind() == reflect.Ptr {
|
||||
isPointer = true
|
||||
elemType = elemType.Elem()
|
||||
}
|
||||
if elemType.Kind() == reflect.Ptr {
|
||||
return errors.New("pointer to pointer is not supported")
|
||||
}
|
||||
|
||||
newElemFunc = func(fields []string) reflect.Value {
|
||||
switch elemType.Kind() {
|
||||
case reflect.Slice:
|
||||
slice := reflect.MakeSlice(elemType, len(fields), len(fields))
|
||||
x := reflect.New(slice.Type())
|
||||
x.Elem().Set(slice)
|
||||
return x
|
||||
case reflect.Map:
|
||||
mp := reflect.MakeMap(elemType)
|
||||
x := reflect.New(mp.Type())
|
||||
x.Elem().Set(mp)
|
||||
return x
|
||||
}
|
||||
return reflect.New(elemType)
|
||||
}
|
||||
|
||||
var containerValueSetFunc func(*reflect.Value, core.PK) error
|
||||
|
||||
if containerValue.Kind() == reflect.Slice {
|
||||
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
|
||||
if isPointer {
|
||||
containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
|
||||
} else {
|
||||
containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
keyType := containerValue.Type().Key()
|
||||
if len(table.PrimaryKeys) == 0 {
|
||||
return errors.New("don't support multiple primary key's map has non-slice key type")
|
||||
}
|
||||
if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
|
||||
return errors.New("don't support multiple primary key's map has non-slice key type")
|
||||
}
|
||||
|
||||
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
|
||||
keyValue := reflect.New(keyType)
|
||||
err := convertPKToValue(table, keyValue.Interface(), pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isPointer {
|
||||
containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
|
||||
} else {
|
||||
containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if elemType.Kind() == reflect.Struct {
|
||||
var newValue = newElemFunc(fields)
|
||||
dataStruct := rValue(newValue.Interface())
|
||||
tb, err := session.engine.autoMapType(dataStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc)
|
||||
rows.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return session.executeProcessors()
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var newValue = newElemFunc(fields)
|
||||
bean := newValue.Interface()
|
||||
|
||||
switch elemType.Kind() {
|
||||
case reflect.Slice:
|
||||
err = rows.ScanSlice(bean)
|
||||
case reflect.Map:
|
||||
err = rows.ScanMap(bean)
|
||||
default:
|
||||
err = rows.Scan(bean)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := containerValueSetFunc(&newValue, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error {
|
||||
cols := table.PKColumns()
|
||||
if len(cols) == 1 {
|
||||
return convertAssign(dst, pk[0])
|
||||
}
|
||||
|
||||
dst = pk
|
||||
return nil
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Get retrieve one record from database, bean's non-empty fields
|
||||
// will be as conditions
|
||||
func (session *Session) Get(bean interface{}) (bool, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
return session.get(bean)
|
||||
}
|
||||
|
||||
func (session *Session) get(bean interface{}) (bool, error) {
|
||||
defer session.resetStatement()
|
||||
|
||||
if session.statement.lastError != nil {
|
||||
return false, session.statement.lastError
|
||||
}
|
||||
|
||||
beanValue := reflect.ValueOf(bean)
|
||||
if beanValue.Kind() != reflect.Ptr {
|
||||
return false, errors.New("needs a pointer to a value")
|
||||
} else if beanValue.Elem().Kind() == reflect.Ptr {
|
||||
return false, errors.New("a pointer to a pointer is not allowed")
|
||||
}
|
||||
|
||||
if beanValue.Elem().Kind() == reflect.Struct {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var err error
|
||||
|
||||
if session.statement.RawSQL == "" {
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return false, ErrTableNotFound
|
||||
}
|
||||
session.statement.Limit(1)
|
||||
sqlStr, args, err = session.statement.genGetSQL(bean)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
sqlStr = session.statement.RawSQL
|
||||
args = session.statement.RawParams
|
||||
}
|
||||
|
||||
table := session.statement.RefTable
|
||||
|
||||
has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
|
||||
if err != nil || !has {
|
||||
return has, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
if rows.Err() != nil {
|
||||
return false, rows.Err()
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch bean := bean.(type) {
|
||||
case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString:
|
||||
return true, rows.Scan(&bean)
|
||||
case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
|
||||
return true, rows.Scan(bean)
|
||||
case *string:
|
||||
var res sql.NullString
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = res.String
|
||||
}
|
||||
return true, nil
|
||||
case *int:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = int(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *int8:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = int8(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *int16:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = int16(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *int32:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = int32(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *int64:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = int64(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *uint:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = uint(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *uint8:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = uint8(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *uint16:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = uint16(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *uint32:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*(bean) = uint32(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *uint64:
|
||||
var res sql.NullInt64
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = uint64(res.Int64)
|
||||
}
|
||||
return true, nil
|
||||
case *bool:
|
||||
var res sql.NullBool
|
||||
if err := rows.Scan(&res); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if res.Valid {
|
||||
*bean = res.Bool
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
switch beanKind {
|
||||
case reflect.Struct:
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
// WARN: Alougth rows return true, but get fields failed
|
||||
return true, err
|
||||
}
|
||||
|
||||
scanResults, err := session.row2Slice(rows, fields, bean)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// close it before covert data
|
||||
rows.Close()
|
||||
|
||||
dataStruct := rValue(bean)
|
||||
_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
return true, session.executeProcessors()
|
||||
case reflect.Slice:
|
||||
err = rows.ScanSlice(bean)
|
||||
case reflect.Map:
|
||||
err = rows.ScanMap(bean)
|
||||
case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
err = rows.Scan(bean)
|
||||
default:
|
||||
err = rows.Scan(bean)
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
||||
@@ -1,824 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// ErrNoElementsOnSlice represents an error there is no element when insert
|
||||
var ErrNoElementsOnSlice = errors.New("no element on slice when insert")
|
||||
|
||||
// Insert insert one or more beans
|
||||
func (session *Session) Insert(beans ...interface{}) (int64, error) {
|
||||
var affected int64
|
||||
var err error
|
||||
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
session.autoResetStatement = false
|
||||
defer func() {
|
||||
session.autoResetStatement = true
|
||||
session.resetStatement()
|
||||
}()
|
||||
|
||||
for _, bean := range beans {
|
||||
switch bean := bean.(type) {
|
||||
case map[string]interface{}:
|
||||
cnt, err := session.insertMapInterface(bean)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
case []map[string]interface{}:
|
||||
for i := 0; i < len(bean); i++ {
|
||||
cnt, err := session.insertMapInterface(bean[i])
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
}
|
||||
case map[string]string:
|
||||
cnt, err := session.insertMapString(bean)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
case []map[string]string:
|
||||
for i := 0; i < len(bean); i++ {
|
||||
cnt, err := session.insertMapString(bean[i])
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
}
|
||||
default:
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(bean))
|
||||
if sliceValue.Kind() == reflect.Slice {
|
||||
size := sliceValue.Len()
|
||||
if size <= 0 {
|
||||
return 0, ErrNoElementsOnSlice
|
||||
}
|
||||
|
||||
if session.engine.SupportInsertMany() {
|
||||
cnt, err := session.innerInsertMulti(bean)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
} else {
|
||||
for i := 0; i < size; i++ {
|
||||
cnt, err := session.innerInsert(sliceValue.Index(i).Interface())
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cnt, err := session.innerInsert(bean)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
affected += cnt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affected, err
|
||||
}
|
||||
|
||||
func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) {
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
|
||||
if sliceValue.Kind() != reflect.Slice {
|
||||
return 0, errors.New("needs a pointer to a slice")
|
||||
}
|
||||
|
||||
if sliceValue.Len() <= 0 {
|
||||
return 0, errors.New("could not insert a empty slice")
|
||||
}
|
||||
|
||||
if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
tableName := session.statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
table := session.statement.RefTable
|
||||
size := sliceValue.Len()
|
||||
|
||||
var colNames []string
|
||||
var colMultiPlaces []string
|
||||
var args []interface{}
|
||||
var cols []*core.Column
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v := sliceValue.Index(i)
|
||||
vv := reflect.Indirect(v)
|
||||
elemValue := v.Interface()
|
||||
var colPlaces []string
|
||||
|
||||
// handle BeforeInsertProcessor
|
||||
// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
|
||||
for _, closure := range session.beforeClosures {
|
||||
closure(elemValue)
|
||||
}
|
||||
|
||||
if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok {
|
||||
processor.BeforeInsert()
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
for _, col := range table.Columns() {
|
||||
ptrFieldValue, err := col.ValueOfV(&vv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
fieldValue := *ptrFieldValue
|
||||
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
|
||||
continue
|
||||
}
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnInt(bean, col, 1)
|
||||
})
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
colNames = append(colNames, col.Name)
|
||||
cols = append(cols, col)
|
||||
colPlaces = append(colPlaces, "?")
|
||||
}
|
||||
} else {
|
||||
for _, col := range cols {
|
||||
ptrFieldValue, err := col.ValueOfV(&vv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
fieldValue := *ptrFieldValue
|
||||
|
||||
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
|
||||
continue
|
||||
}
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnInt(bean, col, 1)
|
||||
})
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
colPlaces = append(colPlaces, "?")
|
||||
}
|
||||
}
|
||||
colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", "))
|
||||
}
|
||||
cleanupProcessorsClosures(&session.beforeClosures)
|
||||
|
||||
var sql string
|
||||
if session.engine.dialect.DBType() == core.ORACLE {
|
||||
temp := fmt.Sprintf(") INTO %s (%v) VALUES (",
|
||||
session.engine.Quote(tableName),
|
||||
quoteColumns(colNames, session.engine.Quote, ","))
|
||||
sql = fmt.Sprintf("INSERT ALL INTO %s (%v) VALUES (%v) SELECT 1 FROM DUAL",
|
||||
session.engine.Quote(tableName),
|
||||
quoteColumns(colNames, session.engine.Quote, ","),
|
||||
strings.Join(colMultiPlaces, temp))
|
||||
} else {
|
||||
sql = fmt.Sprintf("INSERT INTO %s (%v) VALUES (%v)",
|
||||
session.engine.Quote(tableName),
|
||||
quoteColumns(colNames, session.engine.Quote, ","),
|
||||
strings.Join(colMultiPlaces, "),("))
|
||||
}
|
||||
res, err := session.exec(sql, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
lenAfterClosures := len(session.afterClosures)
|
||||
for i := 0; i < size; i++ {
|
||||
elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface()
|
||||
|
||||
// handle AfterInsertProcessor
|
||||
if session.isAutoCommit {
|
||||
// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
|
||||
for _, closure := range session.afterClosures {
|
||||
closure(elemValue)
|
||||
}
|
||||
if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
|
||||
processor.AfterInsert()
|
||||
}
|
||||
} else {
|
||||
if lenAfterClosures > 0 {
|
||||
if value, has := session.afterInsertBeans[elemValue]; has && value != nil {
|
||||
*value = append(*value, session.afterClosures...)
|
||||
} else {
|
||||
afterClosures := make([]func(interface{}), lenAfterClosures)
|
||||
copy(afterClosures, session.afterClosures)
|
||||
session.afterInsertBeans[elemValue] = &afterClosures
|
||||
}
|
||||
} else {
|
||||
if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
|
||||
session.afterInsertBeans[elemValue] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanupProcessorsClosures(&session.afterClosures)
|
||||
return res.RowsAffected()
|
||||
}
|
||||
|
||||
// InsertMulti insert multiple records
|
||||
func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
|
||||
if sliceValue.Kind() != reflect.Slice {
|
||||
return 0, ErrParamsType
|
||||
|
||||
}
|
||||
|
||||
if sliceValue.Len() <= 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return session.innerInsertMulti(rowsSlicePtr)
|
||||
}
|
||||
|
||||
func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
table := session.statement.RefTable
|
||||
|
||||
// handle BeforeInsertProcessor
|
||||
for _, closure := range session.beforeClosures {
|
||||
closure(bean)
|
||||
}
|
||||
cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
|
||||
|
||||
if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
|
||||
processor.BeforeInsert()
|
||||
}
|
||||
|
||||
colNames, args, err := session.genInsertColumns(bean)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
exprs := session.statement.exprColumns
|
||||
colPlaces := strings.Repeat("?, ", len(colNames))
|
||||
if exprs.Len() <= 0 && len(colPlaces) > 0 {
|
||||
colPlaces = colPlaces[0 : len(colPlaces)-2]
|
||||
}
|
||||
|
||||
var tableName = session.statement.TableName()
|
||||
var output string
|
||||
|
||||
var buf = builder.NewWriter()
|
||||
if _, err := buf.WriteString(fmt.Sprintf("INSERT INTO %s", session.engine.Quote(tableName))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(colPlaces) <= 0 {
|
||||
if session.engine.dialect.DBType() == core.MYSQL {
|
||||
if _, err := buf.WriteString(" VALUES ()"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
if _, err := buf.WriteString(fmt.Sprintf("%s DEFAULT VALUES", output)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := buf.WriteString(" ("); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := writeStrings(buf, append(colNames, exprs.colNames...), "`", "`"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if session.statement.cond.IsValid() {
|
||||
if _, err := buf.WriteString(fmt.Sprintf(")%s SELECT ", output)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := session.statement.writeArgs(buf, args); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(exprs.args) > 0 {
|
||||
if _, err := buf.WriteString(","); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if err := exprs.writeArgs(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(fmt.Sprintf(" FROM %v WHERE ", session.engine.Quote(tableName))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := session.statement.cond.WriteTo(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
buf.Append(args...)
|
||||
|
||||
if _, err := buf.WriteString(fmt.Sprintf(")%s VALUES (%v",
|
||||
output,
|
||||
colPlaces)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := exprs.writeArgs(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteString(")"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES {
|
||||
if _, err := buf.WriteString(" RETURNING " + session.engine.Quote(table.AutoIncrement)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
sqlStr := buf.String()
|
||||
args = buf.Args()
|
||||
|
||||
handleAfterInsertProcessorFunc := func(bean interface{}) {
|
||||
if session.isAutoCommit {
|
||||
for _, closure := range session.afterClosures {
|
||||
closure(bean)
|
||||
}
|
||||
if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
|
||||
processor.AfterInsert()
|
||||
}
|
||||
} else {
|
||||
lenAfterClosures := len(session.afterClosures)
|
||||
if lenAfterClosures > 0 {
|
||||
if value, has := session.afterInsertBeans[bean]; has && value != nil {
|
||||
*value = append(*value, session.afterClosures...)
|
||||
} else {
|
||||
afterClosures := make([]func(interface{}), lenAfterClosures)
|
||||
copy(afterClosures, session.afterClosures)
|
||||
session.afterInsertBeans[bean] = &afterClosures
|
||||
}
|
||||
|
||||
} else {
|
||||
if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
|
||||
session.afterInsertBeans[bean] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
|
||||
}
|
||||
|
||||
// for postgres, many of them didn't implement lastInsertId, so we should
|
||||
// implemented it ourself.
|
||||
if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 {
|
||||
res, err := session.queryBytes("select seq_atable.currval from dual", args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer handleAfterInsertProcessorFunc(bean)
|
||||
|
||||
if table.Version != "" && session.statement.checkVersion {
|
||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
} else if verValue.IsValid() && verValue.CanSet() {
|
||||
session.incrVersionFieldValue(verValue)
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) < 1 {
|
||||
return 0, errors.New("insert no error but not returned id")
|
||||
}
|
||||
|
||||
idByte := res[0][table.AutoIncrement]
|
||||
id, err := strconv.ParseInt(string(idByte), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
}
|
||||
|
||||
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
aiValue.Set(int64ToIntValue(id, aiValue.Type()))
|
||||
|
||||
return 1, nil
|
||||
} else if len(table.AutoIncrement) > 0 && (session.engine.dialect.DBType() == core.POSTGRES) {
|
||||
res, err := session.queryBytes(sqlStr, args...)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer handleAfterInsertProcessorFunc(bean)
|
||||
|
||||
if table.Version != "" && session.statement.checkVersion {
|
||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
} else if verValue.IsValid() && verValue.CanSet() {
|
||||
session.incrVersionFieldValue(verValue)
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) < 1 {
|
||||
return 0, errors.New("insert successfully but not returned id")
|
||||
}
|
||||
|
||||
idByte := res[0][table.AutoIncrement]
|
||||
id, err := strconv.ParseInt(string(idByte), 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
}
|
||||
|
||||
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
aiValue.Set(int64ToIntValue(id, aiValue.Type()))
|
||||
|
||||
return 1, nil
|
||||
} else {
|
||||
res, err := session.exec(sqlStr, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer handleAfterInsertProcessorFunc(bean)
|
||||
|
||||
if table.Version != "" && session.statement.checkVersion {
|
||||
verValue, err := table.VersionColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
} else if verValue.IsValid() && verValue.CanSet() {
|
||||
session.incrVersionFieldValue(verValue)
|
||||
}
|
||||
}
|
||||
|
||||
if table.AutoIncrement == "" {
|
||||
return res.RowsAffected()
|
||||
}
|
||||
|
||||
var id int64
|
||||
id, err = res.LastInsertId()
|
||||
if err != nil || id <= 0 {
|
||||
return res.RowsAffected()
|
||||
}
|
||||
|
||||
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
session.engine.logger.Error(err)
|
||||
}
|
||||
|
||||
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
|
||||
return res.RowsAffected()
|
||||
}
|
||||
|
||||
aiValue.Set(int64ToIntValue(id, aiValue.Type()))
|
||||
|
||||
return res.RowsAffected()
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOne insert only one struct into database as a record.
|
||||
// The in parameter bean must a struct or a point to struct. The return
|
||||
// parameter is inserted and error
|
||||
func (session *Session) InsertOne(bean interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
return session.innerInsert(bean)
|
||||
}
|
||||
|
||||
// genInsertColumns generates insert needed columns
|
||||
func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) {
|
||||
table := session.statement.RefTable
|
||||
colNames := make([]string, 0, len(table.ColumnsSeq()))
|
||||
args := make([]interface{}, 0, len(table.ColumnsSeq()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
|
||||
if col.IsDeleted {
|
||||
continue
|
||||
}
|
||||
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if session.statement.incrColumns.isColExist(col.Name) {
|
||||
continue
|
||||
} else if session.statement.decrColumns.isColExist(col.Name) {
|
||||
continue
|
||||
} else if session.statement.exprColumns.isColExist(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fieldValue := *fieldValuePtr
|
||||
|
||||
if col.IsAutoIncrement {
|
||||
switch fieldValue.Type().Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
||||
if fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
||||
if fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if len(fieldValue.String()) == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if fieldValue.Pointer() == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||
if col.Nullable && isZeroValue(fieldValue) {
|
||||
var nilValue *int
|
||||
fieldValue = reflect.ValueOf(nilValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
|
||||
// if time is non-empty, then set to auto time
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return colNames, args, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
colNames = append(colNames, col.Name)
|
||||
}
|
||||
return colNames, args, nil
|
||||
}
|
||||
|
||||
func (session *Session) insertMapInterface(m map[string]interface{}) (int64, error) {
|
||||
if len(m) == 0 {
|
||||
return 0, ErrParamsType
|
||||
}
|
||||
|
||||
tableName := session.statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
var columns = make([]string, 0, len(m))
|
||||
exprs := session.statement.exprColumns
|
||||
for k := range m {
|
||||
if !exprs.isColExist(k) {
|
||||
columns = append(columns, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(columns)
|
||||
|
||||
var args = make([]interface{}, 0, len(m))
|
||||
for _, colName := range columns {
|
||||
args = append(args, m[colName])
|
||||
}
|
||||
|
||||
return session.insertMap(columns, args)
|
||||
}
|
||||
|
||||
func (session *Session) insertMapString(m map[string]string) (int64, error) {
|
||||
if len(m) == 0 {
|
||||
return 0, ErrParamsType
|
||||
}
|
||||
|
||||
tableName := session.statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
var columns = make([]string, 0, len(m))
|
||||
exprs := session.statement.exprColumns
|
||||
for k := range m {
|
||||
if !exprs.isColExist(k) {
|
||||
columns = append(columns, k)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(columns)
|
||||
|
||||
var args = make([]interface{}, 0, len(m))
|
||||
for _, colName := range columns {
|
||||
args = append(args, m[colName])
|
||||
}
|
||||
|
||||
return session.insertMap(columns, args)
|
||||
}
|
||||
|
||||
func (session *Session) insertMap(columns []string, args []interface{}) (int64, error) {
|
||||
tableName := session.statement.TableName()
|
||||
if len(tableName) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
exprs := session.statement.exprColumns
|
||||
w := builder.NewWriter()
|
||||
// if insert where
|
||||
if session.statement.cond.IsValid() {
|
||||
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, err := w.WriteString(") SELECT "); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := session.statement.writeArgs(w, args); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(exprs.args) > 0 {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := exprs.writeArgs(w); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := session.statement.cond.WriteTo(w); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
qm := strings.Repeat("?,", len(columns))
|
||||
qm = qm[:len(qm)-1]
|
||||
|
||||
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := w.WriteString(fmt.Sprintf(") VALUES (%s", qm)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
w.Append(args...)
|
||||
if len(exprs.args) > 0 {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := exprs.writeArgs(w); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if _, err := w.WriteString(")"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
sql := w.String()
|
||||
args = w.Args()
|
||||
|
||||
res, err := session.exec(sql, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
affected, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return affected, nil
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// IterFunc only use by Iterate
|
||||
type IterFunc func(idx int, bean interface{}) error
|
||||
|
||||
// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
|
||||
// are conditions.
|
||||
func (session *Session) Rows(bean interface{}) (*Rows, error) {
|
||||
return newRows(session, bean)
|
||||
}
|
||||
|
||||
// Iterate record by record handle records from table, condiBeans's non-empty fields
|
||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
|
||||
// map[int64]*Struct
|
||||
func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if session.statement.lastError != nil {
|
||||
return session.statement.lastError
|
||||
}
|
||||
|
||||
if session.statement.bufferSize > 0 {
|
||||
return session.bufferIterate(bean, fun)
|
||||
}
|
||||
|
||||
rows, err := session.Rows(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
i := 0
|
||||
for rows.Next() {
|
||||
b := reflect.New(rows.beanType).Interface()
|
||||
err = rows.Scan(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = fun(i, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i++
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
// BufferSize sets the buffersize for iterate
|
||||
func (session *Session) BufferSize(size int) *Session {
|
||||
session.statement.bufferSize = size
|
||||
return session
|
||||
}
|
||||
|
||||
func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
|
||||
var bufferSize = session.statement.bufferSize
|
||||
var pLimitN = session.statement.LimitN
|
||||
if pLimitN != nil && bufferSize > *pLimitN {
|
||||
bufferSize = *pLimitN
|
||||
}
|
||||
var start = session.statement.Start
|
||||
v := rValue(bean)
|
||||
sliceType := reflect.SliceOf(v.Type())
|
||||
var idx = 0
|
||||
session.autoResetStatement = false
|
||||
defer func() {
|
||||
session.autoResetStatement = true
|
||||
}()
|
||||
|
||||
for bufferSize > 0 {
|
||||
slice := reflect.New(sliceType)
|
||||
if err := session.NoCache().Limit(bufferSize, start).find(slice.Interface(), bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < slice.Elem().Len(); i++ {
|
||||
if err := fun(idx, slice.Elem().Index(i).Addr().Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
idx++
|
||||
}
|
||||
|
||||
if bufferSize > slice.Elem().Len() {
|
||||
break
|
||||
}
|
||||
|
||||
start = start + slice.Elem().Len()
|
||||
if pLimitN != nil && start+bufferSize > *pLimitN {
|
||||
bufferSize = *pLimitN - start
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func (session *Session) genQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
||||
if len(sqlOrArgs) > 0 {
|
||||
return convertSQLOrArgs(sqlOrArgs...)
|
||||
}
|
||||
|
||||
if session.statement.RawSQL != "" {
|
||||
return session.statement.RawSQL, session.statement.RawParams, nil
|
||||
}
|
||||
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return "", nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
var columnStr = session.statement.ColumnStr
|
||||
if len(session.statement.selectStr) > 0 {
|
||||
columnStr = session.statement.selectStr
|
||||
} else {
|
||||
if session.statement.JoinStr == "" {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = session.statement.genColumnStr()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if columnStr == "" {
|
||||
if session.statement.GroupByStr != "" {
|
||||
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
|
||||
} else {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
if columnStr == "" {
|
||||
columnStr = "*"
|
||||
}
|
||||
}
|
||||
|
||||
if err := session.statement.processIDParam(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
args := append(session.statement.joinArgs, condArgs...)
|
||||
sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
// for mssql and use limit
|
||||
qs := strings.Count(sqlStr, "?")
|
||||
if len(args)*2 == qs {
|
||||
args = append(args, args...)
|
||||
}
|
||||
|
||||
return sqlStr, args, nil
|
||||
}
|
||||
|
||||
// Query runs a raw sql and return records as []map[string][]byte
|
||||
func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session.queryBytes(sqlStr, args...)
|
||||
}
|
||||
|
||||
func value2String(rawValue *reflect.Value) (str string, err error) {
|
||||
aa := reflect.TypeOf((*rawValue).Interface())
|
||||
vv := reflect.ValueOf((*rawValue).Interface())
|
||||
switch aa.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
str = strconv.FormatInt(vv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
str = strconv.FormatUint(vv.Uint(), 10)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
|
||||
case reflect.String:
|
||||
str = vv.String()
|
||||
case reflect.Array, reflect.Slice:
|
||||
switch aa.Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
data := rawValue.Interface().([]byte)
|
||||
str = string(data)
|
||||
if str == "\x00" {
|
||||
str = "0"
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
||||
}
|
||||
// time type
|
||||
case reflect.Struct:
|
||||
if aa.ConvertibleTo(core.TimeType) {
|
||||
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
|
||||
} else {
|
||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
||||
}
|
||||
case reflect.Bool:
|
||||
str = strconv.FormatBool(vv.Bool())
|
||||
case reflect.Complex128, reflect.Complex64:
|
||||
str = fmt.Sprintf("%v", vv.Complex())
|
||||
/* TODO: unsupported types below
|
||||
case reflect.Map:
|
||||
case reflect.Ptr:
|
||||
case reflect.Uintptr:
|
||||
case reflect.UnsafePointer:
|
||||
case reflect.Chan, reflect.Func, reflect.Interface:
|
||||
*/
|
||||
default:
|
||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
|
||||
result := make(map[string]string)
|
||||
scanResultContainers := make([]interface{}, len(fields))
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var scanResultContainer interface{}
|
||||
scanResultContainers[i] = &scanResultContainer
|
||||
}
|
||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for ii, key := range fields {
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||
// if row is null then as empty string
|
||||
if rawValue.Interface() == nil {
|
||||
result[key] = ""
|
||||
continue
|
||||
}
|
||||
|
||||
if data, err := value2String(&rawValue); err == nil {
|
||||
result[key] = data
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func row2sliceStr(rows *core.Rows, fields []string) (results []string, err error) {
|
||||
result := make([]string, 0, len(fields))
|
||||
scanResultContainers := make([]interface{}, len(fields))
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var scanResultContainer interface{}
|
||||
scanResultContainers[i] = &scanResultContainer
|
||||
}
|
||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(fields); i++ {
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[i]))
|
||||
// if row is null then as empty string
|
||||
if rawValue.Interface() == nil {
|
||||
result = append(result, "")
|
||||
continue
|
||||
}
|
||||
|
||||
if data, err := value2String(&rawValue); err == nil {
|
||||
result = append(result, data)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
result, err := row2mapStr(rows, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultsSlice = append(resultsSlice, result)
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return nil, rows.Err()
|
||||
}
|
||||
|
||||
return resultsSlice, nil
|
||||
}
|
||||
|
||||
func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
record, err := row2sliceStr(rows, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultsSlice = append(resultsSlice, record)
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return nil, rows.Err()
|
||||
}
|
||||
|
||||
return resultsSlice, nil
|
||||
}
|
||||
|
||||
// QueryString runs a raw sql and return records as []map[string]string
|
||||
func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return rows2Strings(rows)
|
||||
}
|
||||
|
||||
// QuerySliceString runs a raw sql and return records as [][]string
|
||||
func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return rows2SliceString(rows)
|
||||
}
|
||||
|
||||
func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
|
||||
resultsMap = make(map[string]interface{}, len(fields))
|
||||
scanResultContainers := make([]interface{}, len(fields))
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var scanResultContainer interface{}
|
||||
scanResultContainers[i] = &scanResultContainer
|
||||
}
|
||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for ii, key := range fields {
|
||||
resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
result, err := row2mapInterface(rows, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultsSlice = append(resultsSlice, result)
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return nil, rows.Err()
|
||||
}
|
||||
|
||||
return resultsSlice, nil
|
||||
}
|
||||
|
||||
// QueryInterface runs a raw sql and return records as []map[string]interface{}
|
||||
func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return rows2Interfaces(rows)
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
|
||||
for _, filter := range session.engine.dialect.Filters() {
|
||||
*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable)
|
||||
}
|
||||
|
||||
session.lastSQL = *sqlStr
|
||||
session.lastSQLArgs = paramStr
|
||||
}
|
||||
|
||||
func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) {
|
||||
defer session.resetStatement()
|
||||
|
||||
session.queryPreprocess(&sqlStr, args...)
|
||||
|
||||
if session.showSQL {
|
||||
session.lastSQL = sqlStr
|
||||
session.lastSQLArgs = args
|
||||
if session.engine.showExecTime {
|
||||
b4ExecTime := time.Now()
|
||||
defer func() {
|
||||
execDuration := time.Since(b4ExecTime)
|
||||
if len(args) > 0 {
|
||||
session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
|
||||
} else {
|
||||
session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
if len(args) > 0 {
|
||||
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
|
||||
} else {
|
||||
session.engine.logger.Infof("[SQL] %v", sqlStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if session.isAutoCommit {
|
||||
db := session.DB()
|
||||
if session.prepareStmt {
|
||||
// don't clear stmt since session will cache them
|
||||
stmt, err := session.doPrepare(db, sqlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := stmt.QueryContext(session.ctx, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
rows, err := db.QueryContext(session.ctx, sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
|
||||
return core.NewRow(session.queryRows(sqlStr, args...))
|
||||
}
|
||||
|
||||
func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
|
||||
str, err := value2String(rawValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(str), nil
|
||||
}
|
||||
|
||||
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
|
||||
result := make(map[string][]byte)
|
||||
scanResultContainers := make([]interface{}, len(fields))
|
||||
for i := 0; i < len(fields); i++ {
|
||||
var scanResultContainer interface{}
|
||||
scanResultContainers[i] = &scanResultContainer
|
||||
}
|
||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for ii, key := range fields {
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||
//if row is null then ignore
|
||||
if rawValue.Interface() == nil {
|
||||
result[key] = []byte{}
|
||||
continue
|
||||
}
|
||||
|
||||
if data, err := value2Bytes(&rawValue); err == nil {
|
||||
result[key] = data
|
||||
} else {
|
||||
return nil, err // !nashtsai! REVIEW, should return err or just error log?
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
|
||||
fields, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
result, err := row2map(rows, fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultsSlice = append(resultsSlice, result)
|
||||
}
|
||||
|
||||
return resultsSlice, nil
|
||||
}
|
||||
|
||||
func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
|
||||
rows, err := session.queryRows(sqlStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return rows2maps(rows)
|
||||
}
|
||||
|
||||
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
|
||||
defer session.resetStatement()
|
||||
|
||||
session.queryPreprocess(&sqlStr, args...)
|
||||
|
||||
if session.engine.showSQL {
|
||||
if session.engine.showExecTime {
|
||||
b4ExecTime := time.Now()
|
||||
defer func() {
|
||||
execDuration := time.Since(b4ExecTime)
|
||||
if len(args) > 0 {
|
||||
session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
|
||||
} else {
|
||||
session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
if len(args) > 0 {
|
||||
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
|
||||
} else {
|
||||
session.engine.logger.Infof("[SQL] %v", sqlStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !session.isAutoCommit {
|
||||
return session.tx.ExecContext(session.ctx, sqlStr, args...)
|
||||
}
|
||||
|
||||
if session.prepareStmt {
|
||||
stmt, err := session.doPrepare(session.DB(), sqlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := stmt.ExecContext(session.ctx, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return session.DB().ExecContext(session.ctx, sqlStr, args...)
|
||||
}
|
||||
|
||||
func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
|
||||
switch sqlOrArgs[0].(type) {
|
||||
case string:
|
||||
return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
|
||||
case *builder.Builder:
|
||||
return sqlOrArgs[0].(*builder.Builder).ToSQL()
|
||||
case builder.Builder:
|
||||
bd := sqlOrArgs[0].(builder.Builder)
|
||||
return bd.ToSQL()
|
||||
}
|
||||
|
||||
return "", nil, ErrUnSupportedType
|
||||
}
|
||||
|
||||
// Exec raw sql
|
||||
func (session *Session) Exec(sqlOrArgs ...interface{}) (sql.Result, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if len(sqlOrArgs) == 0 {
|
||||
return nil, ErrUnSupportedType
|
||||
}
|
||||
|
||||
sqlStr, args, err := convertSQLOrArgs(sqlOrArgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session.exec(sqlStr, args...)
|
||||
}
|
||||
@@ -1,432 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Ping test if database is ok
|
||||
func (session *Session) Ping() error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
|
||||
return session.DB().PingContext(session.ctx)
|
||||
}
|
||||
|
||||
// CreateTable create a table according a bean
|
||||
func (session *Session) CreateTable(bean interface{}) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
return session.createTable(bean)
|
||||
}
|
||||
|
||||
func (session *Session) createTable(bean interface{}) error {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqlStr := session.statement.genCreateTableSQL()
|
||||
_, err := session.exec(sqlStr)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateIndexes create indexes
|
||||
func (session *Session) CreateIndexes(bean interface{}) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
return session.createIndexes(bean)
|
||||
}
|
||||
|
||||
func (session *Session) createIndexes(bean interface{}) error {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqls := session.statement.genIndexSQL()
|
||||
for _, sqlStr := range sqls {
|
||||
_, err := session.exec(sqlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateUniques create uniques
|
||||
func (session *Session) CreateUniques(bean interface{}) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
return session.createUniques(bean)
|
||||
}
|
||||
|
||||
func (session *Session) createUniques(bean interface{}) error {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqls := session.statement.genUniqueSQL()
|
||||
for _, sqlStr := range sqls {
|
||||
_, err := session.exec(sqlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropIndexes drop indexes
|
||||
func (session *Session) DropIndexes(bean interface{}) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
return session.dropIndexes(bean)
|
||||
}
|
||||
|
||||
func (session *Session) dropIndexes(bean interface{}) error {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqls := session.statement.genDelIndexSQL()
|
||||
for _, sqlStr := range sqls {
|
||||
_, err := session.exec(sqlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropTable drop table will drop table if exist, if drop failed, it will return error
|
||||
func (session *Session) DropTable(beanOrTableName interface{}) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
return session.dropTable(beanOrTableName)
|
||||
}
|
||||
|
||||
func (session *Session) dropTable(beanOrTableName interface{}) error {
|
||||
tableName := session.engine.TableName(beanOrTableName)
|
||||
var needDrop = true
|
||||
if !session.engine.dialect.SupportDropIfExists() {
|
||||
sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
|
||||
results, err := session.queryBytes(sqlStr, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needDrop = len(results) > 0
|
||||
}
|
||||
|
||||
if needDrop {
|
||||
sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true))
|
||||
_, err := session.exec(sqlStr)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsTableExist if a table is exist
|
||||
func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
tableName := session.engine.TableName(beanOrTableName)
|
||||
|
||||
return session.isTableExist(tableName)
|
||||
}
|
||||
|
||||
func (session *Session) isTableExist(tableName string) (bool, error) {
|
||||
sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
|
||||
results, err := session.queryBytes(sqlStr, args...)
|
||||
return len(results) > 0, err
|
||||
}
|
||||
|
||||
// IsTableEmpty if table have any records
|
||||
func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
return session.isTableEmpty(session.engine.TableName(bean))
|
||||
}
|
||||
|
||||
func (session *Session) isTableEmpty(tableName string) (bool, error) {
|
||||
var total int64
|
||||
sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true)))
|
||||
err := session.queryRow(sqlStr).Scan(&total)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
return total == 0, nil
|
||||
}
|
||||
|
||||
// find if index is exist according cols
|
||||
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
|
||||
indexes, err := session.engine.dialect.GetIndexes(tableName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, index := range indexes {
|
||||
if sliceEq(index.Cols, cols) {
|
||||
if unique {
|
||||
return index.Type == core.UniqueType, nil
|
||||
}
|
||||
return index.Type == core.IndexType, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (session *Session) addColumn(colName string) error {
|
||||
col := session.statement.RefTable.GetColumn(colName)
|
||||
sql, args := session.statement.genAddColumnStr(col)
|
||||
_, err := session.exec(sql, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (session *Session) addIndex(tableName, idxName string) error {
|
||||
index := session.statement.RefTable.Indexes[idxName]
|
||||
sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
|
||||
_, err := session.exec(sqlStr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (session *Session) addUnique(tableName, uqeName string) error {
|
||||
index := session.statement.RefTable.Indexes[uqeName]
|
||||
sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
|
||||
_, err := session.exec(sqlStr)
|
||||
return err
|
||||
}
|
||||
|
||||
// Sync2 synchronize structs to database tables
|
||||
func (session *Session) Sync2(beans ...interface{}) error {
|
||||
engine := session.engine
|
||||
|
||||
if session.isAutoClose {
|
||||
session.isAutoClose = false
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
tables, err := engine.dialect.GetTables()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session.autoResetStatement = false
|
||||
defer func() {
|
||||
session.autoResetStatement = true
|
||||
session.resetStatement()
|
||||
}()
|
||||
|
||||
for _, bean := range beans {
|
||||
v := rValue(bean)
|
||||
table, err := engine.mapType(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var tbName string
|
||||
if len(session.statement.AltTableName) > 0 {
|
||||
tbName = session.statement.AltTableName
|
||||
} else {
|
||||
tbName = engine.TableName(bean)
|
||||
}
|
||||
tbNameWithSchema := engine.tbNameWithSchema(tbName)
|
||||
|
||||
var oriTable *core.Table
|
||||
for _, tb := range tables {
|
||||
if strings.EqualFold(engine.tbNameWithSchema(tb.Name), engine.tbNameWithSchema(tbName)) {
|
||||
oriTable = tb
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// this is a new table
|
||||
if oriTable == nil {
|
||||
err = session.StoreEngine(session.statement.StoreEngine).createTable(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = session.createUniques(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = session.createIndexes(bean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// this will modify an old table
|
||||
if err = engine.loadTableInfo(oriTable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check columns
|
||||
for _, col := range table.Columns() {
|
||||
var oriCol *core.Column
|
||||
for _, col2 := range oriTable.Columns() {
|
||||
if strings.EqualFold(col.Name, col2.Name) {
|
||||
oriCol = col2
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// column is not exist on table
|
||||
if oriCol == nil {
|
||||
session.statement.RefTable = table
|
||||
session.statement.tableName = tbNameWithSchema
|
||||
if err = session.addColumn(col.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
err = nil
|
||||
expectedType := engine.dialect.SqlType(col)
|
||||
curType := engine.dialect.SqlType(oriCol)
|
||||
if expectedType != curType {
|
||||
if expectedType == core.Text &&
|
||||
strings.HasPrefix(curType, core.Varchar) {
|
||||
// currently only support mysql & postgres
|
||||
if engine.dialect.DBType() == core.MYSQL ||
|
||||
engine.dialect.DBType() == core.POSTGRES {
|
||||
engine.logger.Infof("Table %s column %s change type from %s to %s\n",
|
||||
tbNameWithSchema, col.Name, curType, expectedType)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
|
||||
} else {
|
||||
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
|
||||
tbNameWithSchema, col.Name, curType, expectedType)
|
||||
}
|
||||
} else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
|
||||
if engine.dialect.DBType() == core.MYSQL {
|
||||
if oriCol.Length < col.Length {
|
||||
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
|
||||
tbNameWithSchema, col.Name, oriCol.Length, col.Length)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
|
||||
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
|
||||
tbNameWithSchema, col.Name, curType, expectedType)
|
||||
}
|
||||
}
|
||||
} else if expectedType == core.Varchar {
|
||||
if engine.dialect.DBType() == core.MYSQL {
|
||||
if oriCol.Length < col.Length {
|
||||
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
|
||||
tbNameWithSchema, col.Name, oriCol.Length, col.Length)
|
||||
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if col.Default != oriCol.Default {
|
||||
switch {
|
||||
case col.IsAutoIncrement: // For autoincrement column, don't check default
|
||||
case (col.SQLType.Name == core.Bool || col.SQLType.Name == core.Boolean) &&
|
||||
((strings.EqualFold(col.Default, "true") && oriCol.Default == "1") ||
|
||||
(strings.EqualFold(col.Default, "false") && oriCol.Default == "0")):
|
||||
default:
|
||||
engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s",
|
||||
tbName, col.Name, oriCol.Default, col.Default)
|
||||
}
|
||||
}
|
||||
if col.Nullable != oriCol.Nullable {
|
||||
engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v",
|
||||
tbName, col.Name, oriCol.Nullable, col.Nullable)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var foundIndexNames = make(map[string]bool)
|
||||
var addedNames = make(map[string]*core.Index)
|
||||
|
||||
for name, index := range table.Indexes {
|
||||
var oriIndex *core.Index
|
||||
for name2, index2 := range oriTable.Indexes {
|
||||
if index.Equal(index2) {
|
||||
oriIndex = index2
|
||||
foundIndexNames[name2] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if oriIndex != nil {
|
||||
if oriIndex.Type != index.Type {
|
||||
sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex)
|
||||
_, err = session.exec(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oriIndex = nil
|
||||
}
|
||||
}
|
||||
|
||||
if oriIndex == nil {
|
||||
addedNames[name] = index
|
||||
}
|
||||
}
|
||||
|
||||
for name2, index2 := range oriTable.Indexes {
|
||||
if _, ok := foundIndexNames[name2]; !ok {
|
||||
sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2)
|
||||
_, err = session.exec(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for name, index := range addedNames {
|
||||
if index.Type == core.UniqueType {
|
||||
session.statement.RefTable = table
|
||||
session.statement.tableName = tbNameWithSchema
|
||||
err = session.addUnique(tbNameWithSchema, name)
|
||||
} else if index.Type == core.IndexType {
|
||||
session.statement.RefTable = table
|
||||
session.statement.tableName = tbNameWithSchema
|
||||
err = session.addIndex(tbNameWithSchema, name)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// check all the columns which removed from struct fields but left on database tables.
|
||||
for _, colName := range oriTable.ColumnsSeq() {
|
||||
if table.GetColumn(colName) == nil {
|
||||
engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(oriTable.Name, true), colName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Count counts the records. bean's non-empty fields
|
||||
// are conditions.
|
||||
func (session *Session) Count(bean ...interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var err error
|
||||
if session.statement.RawSQL == "" {
|
||||
sqlStr, args, err = session.statement.genCountSQL(bean...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
sqlStr = session.statement.RawSQL
|
||||
args = session.statement.RawParams
|
||||
}
|
||||
|
||||
var total int64
|
||||
err = session.queryRow(sqlStr, args...).Scan(&total)
|
||||
if err == sql.ErrNoRows || err == nil {
|
||||
return total, nil
|
||||
}
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// sum call sum some column. bean's non-empty fields are conditions.
|
||||
func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(res)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return errors.New("need a pointer to a variable")
|
||||
}
|
||||
|
||||
var isSlice = v.Elem().Kind() == reflect.Slice
|
||||
var sqlStr string
|
||||
var args []interface{}
|
||||
var err error
|
||||
if len(session.statement.RawSQL) == 0 {
|
||||
sqlStr, args, err = session.statement.genSumSQL(bean, columnNames...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
sqlStr = session.statement.RawSQL
|
||||
args = session.statement.RawParams
|
||||
}
|
||||
|
||||
if isSlice {
|
||||
err = session.queryRow(sqlStr, args...).ScanSlice(res)
|
||||
} else {
|
||||
err = session.queryRow(sqlStr, args...).Scan(res)
|
||||
}
|
||||
if err == sql.ErrNoRows || err == nil {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Sum call sum some column. bean's non-empty fields are conditions.
|
||||
func (session *Session) Sum(bean interface{}, columnName string) (res float64, err error) {
|
||||
return res, session.sum(&res, bean, columnName)
|
||||
}
|
||||
|
||||
// SumInt call sum some column. bean's non-empty fields are conditions.
|
||||
func (session *Session) SumInt(bean interface{}, columnName string) (res int64, err error) {
|
||||
return res, session.sum(&res, bean, columnName)
|
||||
}
|
||||
|
||||
// Sums call sum some columns. bean's non-empty fields are conditions.
|
||||
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
|
||||
var res = make([]float64, len(columnNames), len(columnNames))
|
||||
return res, session.sum(&res, bean, columnNames...)
|
||||
}
|
||||
|
||||
// SumsInt sum specify columns and return as []int64 instead of []float64
|
||||
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
|
||||
var res = make([]int64, len(columnNames), len(columnNames))
|
||||
return res, session.sum(&res, bean, columnNames...)
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
// Begin a transaction
|
||||
func (session *Session) Begin() error {
|
||||
if session.isAutoCommit {
|
||||
tx, err := session.DB().BeginTx(session.ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.isAutoCommit = false
|
||||
session.isCommitedOrRollbacked = false
|
||||
session.tx = tx
|
||||
session.saveLastSQL("BEGIN TRANSACTION")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rollback When using transaction, you can rollback if any error
|
||||
func (session *Session) Rollback() error {
|
||||
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
|
||||
session.saveLastSQL(session.engine.dialect.RollBackStr())
|
||||
session.isCommitedOrRollbacked = true
|
||||
session.isAutoCommit = true
|
||||
return session.tx.Rollback()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Commit When using transaction, Commit will commit all operations.
|
||||
func (session *Session) Commit() error {
|
||||
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
|
||||
session.saveLastSQL("COMMIT")
|
||||
session.isCommitedOrRollbacked = true
|
||||
session.isAutoCommit = true
|
||||
var err error
|
||||
if err = session.tx.Commit(); err == nil {
|
||||
// handle processors after tx committed
|
||||
closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
|
||||
if closuresPtr != nil {
|
||||
for _, closure := range *closuresPtr {
|
||||
closure(bean)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for bean, closuresPtr := range session.afterInsertBeans {
|
||||
closureCallFunc(closuresPtr, bean)
|
||||
|
||||
if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
|
||||
processor.AfterInsert()
|
||||
}
|
||||
}
|
||||
for bean, closuresPtr := range session.afterUpdateBeans {
|
||||
closureCallFunc(closuresPtr, bean)
|
||||
|
||||
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
|
||||
processor.AfterUpdate()
|
||||
}
|
||||
}
|
||||
for bean, closuresPtr := range session.afterDeleteBeans {
|
||||
closureCallFunc(closuresPtr, bean)
|
||||
|
||||
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
|
||||
processor.AfterDelete()
|
||||
}
|
||||
}
|
||||
cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
|
||||
if len(*slices) > 0 {
|
||||
*slices = make(map[interface{}]*[]func(interface{}), 0)
|
||||
}
|
||||
}
|
||||
cleanUpFunc(&session.afterInsertBeans)
|
||||
cleanUpFunc(&session.afterUpdateBeans)
|
||||
cleanUpFunc(&session.afterDeleteBeans)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,397 +0,0 @@
|
||||
// Copyright 2016 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
// Update records, bean's non-empty fields are updated contents,
|
||||
// condiBean' non-empty filds are conditions
|
||||
// CAUTION:
|
||||
//
|
||||
// 1.bool will defaultly be updated content nor conditions
|
||||
// You should call UseBool if you have bool to use.
|
||||
// 2.float32 & float64 may be not inexact as conditions
|
||||
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
|
||||
if session.isAutoClose {
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
if session.statement.lastError != nil {
|
||||
return 0, session.statement.lastError
|
||||
}
|
||||
|
||||
v := rValue(bean)
|
||||
t := v.Type()
|
||||
|
||||
var colNames []string
|
||||
var args []interface{}
|
||||
|
||||
// handle before update processors
|
||||
for _, closure := range session.beforeClosures {
|
||||
closure(bean)
|
||||
}
|
||||
cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
|
||||
if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok {
|
||||
processor.BeforeUpdate()
|
||||
}
|
||||
// --
|
||||
|
||||
var err error
|
||||
var isMap = t.Kind() == reflect.Map
|
||||
var isStruct = t.Kind() == reflect.Struct
|
||||
if isStruct {
|
||||
if err := session.statement.setRefBean(bean); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(session.statement.TableName()) <= 0 {
|
||||
return 0, ErrTableNotFound
|
||||
}
|
||||
|
||||
if session.statement.ColumnStr == "" {
|
||||
colNames, args = session.statement.buildUpdates(bean, false, false,
|
||||
false, false, true)
|
||||
} else {
|
||||
colNames, args, err = session.genUpdateColumns(bean)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
} else if isMap {
|
||||
colNames = make([]string, 0)
|
||||
args = make([]interface{}, 0)
|
||||
bValue := reflect.Indirect(reflect.ValueOf(bean))
|
||||
|
||||
for _, v := range bValue.MapKeys() {
|
||||
colNames = append(colNames, session.engine.Quote(v.String())+" = ?")
|
||||
args = append(args, bValue.MapIndex(v).Interface())
|
||||
}
|
||||
} else {
|
||||
return 0, ErrParamsType
|
||||
}
|
||||
|
||||
table := session.statement.RefTable
|
||||
|
||||
if session.statement.UseAutoTime && table != nil && table.Updated != "" {
|
||||
if !session.statement.columnMap.contain(table.Updated) &&
|
||||
!session.statement.omitColumnMap.contain(table.Updated) {
|
||||
colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
|
||||
col := table.UpdatedColumn()
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
if isStruct {
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for update action to like "column = column + ?"
|
||||
incColumns := session.statement.incrColumns
|
||||
for i, colName := range incColumns.colNames {
|
||||
colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" + ?")
|
||||
args = append(args, incColumns.args[i])
|
||||
}
|
||||
// for update action to like "column = column - ?"
|
||||
decColumns := session.statement.decrColumns
|
||||
for i, colName := range decColumns.colNames {
|
||||
colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" - ?")
|
||||
args = append(args, decColumns.args[i])
|
||||
}
|
||||
// for update action to like "column = expression"
|
||||
exprColumns := session.statement.exprColumns
|
||||
for i, colName := range exprColumns.colNames {
|
||||
switch tp := exprColumns.args[i].(type) {
|
||||
case string:
|
||||
if len(tp) == 0 {
|
||||
tp = "''"
|
||||
}
|
||||
colNames = append(colNames, session.engine.Quote(colName)+"="+tp)
|
||||
case *builder.Builder:
|
||||
subQuery, subArgs, err := builder.ToSQL(tp)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
colNames = append(colNames, session.engine.Quote(colName)+"=("+subQuery+")")
|
||||
args = append(args, subArgs...)
|
||||
default:
|
||||
colNames = append(colNames, session.engine.Quote(colName)+"=?")
|
||||
args = append(args, exprColumns.args[i])
|
||||
}
|
||||
}
|
||||
|
||||
if err = session.statement.processIDParam(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var autoCond builder.Cond
|
||||
if !session.statement.noAutoCondition {
|
||||
condBeanIsStruct := false
|
||||
if len(condiBean) > 0 {
|
||||
if c, ok := condiBean[0].(map[string]interface{}); ok {
|
||||
autoCond = builder.Eq(c)
|
||||
} else {
|
||||
ct := reflect.TypeOf(condiBean[0])
|
||||
k := ct.Kind()
|
||||
if k == reflect.Ptr {
|
||||
k = ct.Elem().Kind()
|
||||
}
|
||||
if k == reflect.Struct {
|
||||
var err error
|
||||
autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
condBeanIsStruct = true
|
||||
} else {
|
||||
return 0, ErrConditionType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !condBeanIsStruct && table != nil {
|
||||
if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
|
||||
autoCond1 := session.engine.CondDeleted(col)
|
||||
|
||||
if autoCond == nil {
|
||||
autoCond = autoCond1
|
||||
} else {
|
||||
autoCond = autoCond.And(autoCond1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st := &session.statement
|
||||
|
||||
var (
|
||||
sqlStr string
|
||||
condArgs []interface{}
|
||||
condSQL string
|
||||
cond = session.statement.cond.And(autoCond)
|
||||
|
||||
doIncVer = isStruct && (table != nil && table.Version != "" && session.statement.checkVersion)
|
||||
verValue *reflect.Value
|
||||
)
|
||||
if doIncVer {
|
||||
verValue, err = table.VersionColumn().ValueOf(bean)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if verValue != nil {
|
||||
cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()})
|
||||
colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1")
|
||||
}
|
||||
}
|
||||
|
||||
condSQL, condArgs, err = builder.ToSQL(cond)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(condSQL) > 0 {
|
||||
condSQL = "WHERE " + condSQL
|
||||
}
|
||||
|
||||
if st.OrderStr != "" {
|
||||
condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
|
||||
}
|
||||
|
||||
var tableName = session.statement.TableName()
|
||||
// TODO: Oracle support needed
|
||||
var top string
|
||||
if st.LimitN != nil {
|
||||
limitValue := *st.LimitN
|
||||
if st.Engine.dialect.DBType() == core.MYSQL {
|
||||
condSQL = condSQL + fmt.Sprintf(" LIMIT %d", limitValue)
|
||||
} else if st.Engine.dialect.DBType() == core.SQLITE {
|
||||
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue)
|
||||
cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)",
|
||||
session.engine.Quote(tableName), tempCondSQL), condArgs...))
|
||||
condSQL, condArgs, err = builder.ToSQL(cond)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(condSQL) > 0 {
|
||||
condSQL = "WHERE " + condSQL
|
||||
}
|
||||
} else if st.Engine.dialect.DBType() == core.POSTGRES {
|
||||
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", limitValue)
|
||||
cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)",
|
||||
session.engine.Quote(tableName), tempCondSQL), condArgs...))
|
||||
condSQL, condArgs, err = builder.ToSQL(cond)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(condSQL) > 0 {
|
||||
condSQL = "WHERE " + condSQL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(colNames) <= 0 {
|
||||
return 0, errors.New("no content found to be updated")
|
||||
}
|
||||
|
||||
var tableAlias = session.engine.Quote(tableName)
|
||||
var fromSQL string
|
||||
if session.statement.TableAlias != "" {
|
||||
tableAlias = fmt.Sprintf("%s AS %s", tableAlias, session.statement.TableAlias)
|
||||
}
|
||||
|
||||
sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v%v",
|
||||
top,
|
||||
tableAlias,
|
||||
strings.Join(colNames, ", "),
|
||||
fromSQL,
|
||||
condSQL)
|
||||
|
||||
res, err := session.exec(sqlStr, append(args, condArgs...)...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if doIncVer {
|
||||
if verValue != nil && verValue.IsValid() && verValue.CanSet() {
|
||||
session.incrVersionFieldValue(verValue)
|
||||
}
|
||||
}
|
||||
|
||||
// handle after update processors
|
||||
if session.isAutoCommit {
|
||||
for _, closure := range session.afterClosures {
|
||||
closure(bean)
|
||||
}
|
||||
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
|
||||
session.engine.logger.Debug("[event]", tableName, " has after update processor")
|
||||
processor.AfterUpdate()
|
||||
}
|
||||
} else {
|
||||
lenAfterClosures := len(session.afterClosures)
|
||||
if lenAfterClosures > 0 {
|
||||
if value, has := session.afterUpdateBeans[bean]; has && value != nil {
|
||||
*value = append(*value, session.afterClosures...)
|
||||
} else {
|
||||
afterClosures := make([]func(interface{}), lenAfterClosures)
|
||||
copy(afterClosures, session.afterClosures)
|
||||
// FIXME: if bean is a map type, it will panic because map cannot be as map key
|
||||
session.afterUpdateBeans[bean] = &afterClosures
|
||||
}
|
||||
|
||||
} else {
|
||||
if _, ok := interface{}(bean).(AfterUpdateProcessor); ok {
|
||||
session.afterUpdateBeans[bean] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
|
||||
// --
|
||||
|
||||
return res.RowsAffected()
|
||||
}
|
||||
|
||||
func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interface{}, error) {
|
||||
table := session.statement.RefTable
|
||||
colNames := make([]string, 0, len(table.ColumnsSeq()))
|
||||
args := make([]interface{}, 0, len(table.ColumnsSeq()))
|
||||
|
||||
for _, col := range table.Columns() {
|
||||
if !col.IsVersion && !col.IsCreated && !col.IsUpdated {
|
||||
if session.statement.omitColumnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if col.MapType == core.ONLYFROMDB {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValuePtr, err := col.ValueOf(bean)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fieldValue := *fieldValuePtr
|
||||
|
||||
if col.IsAutoIncrement {
|
||||
switch fieldValue.Type().Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
||||
if fieldValue.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
||||
if fieldValue.Uint() == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.String:
|
||||
if len(fieldValue.String()) == 0 {
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if fieldValue.Pointer() == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (col.IsDeleted && !session.statement.unscoped) || col.IsCreated {
|
||||
continue
|
||||
}
|
||||
|
||||
// if only update specify columns
|
||||
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if session.statement.incrColumns.isColExist(col.Name) {
|
||||
continue
|
||||
} else if session.statement.decrColumns.isColExist(col.Name) {
|
||||
continue
|
||||
} else if session.statement.exprColumns.isColExist(col.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
|
||||
if col.Nullable && isZeroValue(fieldValue) {
|
||||
var nilValue *int
|
||||
fieldValue = reflect.ValueOf(nilValue)
|
||||
}
|
||||
}
|
||||
|
||||
if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
|
||||
// if time is non-empty, then set to auto time
|
||||
val, t := session.engine.nowTime(col)
|
||||
args = append(args, val)
|
||||
|
||||
var colName = col.Name
|
||||
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
||||
col := table.GetColumn(colName)
|
||||
setColumnTime(bean, col, t)
|
||||
})
|
||||
} else if col.IsVersion && session.statement.checkVersion {
|
||||
args = append(args, 1)
|
||||
} else {
|
||||
arg, err := session.value2Interface(col, fieldValue)
|
||||
if err != nil {
|
||||
return colNames, args, err
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
|
||||
}
|
||||
return colNames, args, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,158 +0,0 @@
|
||||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func quoteNeeded(a interface{}) bool {
|
||||
switch a.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
return false
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return false
|
||||
case float32, float64:
|
||||
return false
|
||||
case bool:
|
||||
return false
|
||||
case string:
|
||||
return true
|
||||
case time.Time, *time.Time:
|
||||
return true
|
||||
case builder.Builder, *builder.Builder:
|
||||
return false
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(a)
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return false
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return false
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return false
|
||||
case reflect.Bool:
|
||||
return false
|
||||
case reflect.String:
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func convertStringSingleQuote(arg string) string {
|
||||
return "'" + strings.Replace(arg, "'", "''", -1) + "'"
|
||||
}
|
||||
|
||||
func convertString(arg string) string {
|
||||
var buf strings.Builder
|
||||
buf.WriteRune('\'')
|
||||
for _, c := range arg {
|
||||
if c == '\\' || c == '\'' {
|
||||
buf.WriteRune('\\')
|
||||
}
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
buf.WriteRune('\'')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func convertArg(arg interface{}, convertFunc func(string) string) string {
|
||||
if quoteNeeded(arg) {
|
||||
argv := fmt.Sprintf("%v", arg)
|
||||
return convertFunc(argv)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", arg)
|
||||
}
|
||||
|
||||
const insertSelectPlaceHolder = true
|
||||
|
||||
func (statement *Statement) writeArg(w *builder.BytesWriter, arg interface{}) error {
|
||||
switch argv := arg.(type) {
|
||||
case bool:
|
||||
if argv {
|
||||
if _, err := w.WriteString("true"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := w.WriteString("false"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *builder.Builder:
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := argv.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(")"); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if insertSelectPlaceHolder {
|
||||
if err := w.WriteByte('?'); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(arg)
|
||||
} else {
|
||||
var convertFunc = convertStringSingleQuote
|
||||
if statement.Engine.dialect.DBType() == core.MYSQL {
|
||||
convertFunc = convertString
|
||||
}
|
||||
if _, err := w.WriteString(convertArg(arg, convertFunc)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (statement *Statement) writeArgs(w *builder.BytesWriter, args []interface{}) error {
|
||||
for i, arg := range args {
|
||||
if err := statement.writeArg(w, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i+1 != len(args) {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeStrings(w *builder.BytesWriter, cols []string, leftQuote, rightQuote string) error {
|
||||
for i, colName := range cols {
|
||||
if len(leftQuote) > 0 && colName[0] != '`' {
|
||||
if _, err := w.WriteString(leftQuote); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := w.WriteString(colName); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(rightQuote) > 0 && colName[len(colName)-1] != '`' {
|
||||
if _, err := w.WriteString(rightQuote); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if i+1 != len(cols) {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import "strings"
|
||||
|
||||
type columnMap []string
|
||||
|
||||
func (m columnMap) contain(colName string) bool {
|
||||
if len(m) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
n := len(colName)
|
||||
for _, mk := range m {
|
||||
if len(mk) != n {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(mk, colName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *columnMap) add(colName string) bool {
|
||||
if m.contain(colName) {
|
||||
return false
|
||||
}
|
||||
*m = append(*m, colName)
|
||||
return true
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type ErrUnsupportedExprType struct {
|
||||
tp string
|
||||
}
|
||||
|
||||
func (err ErrUnsupportedExprType) Error() string {
|
||||
return fmt.Sprintf("Unsupported expression type: %v", err.tp)
|
||||
}
|
||||
|
||||
type exprParam struct {
|
||||
colName string
|
||||
arg interface{}
|
||||
}
|
||||
|
||||
type exprParams struct {
|
||||
colNames []string
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
func (exprs *exprParams) Len() int {
|
||||
return len(exprs.colNames)
|
||||
}
|
||||
|
||||
func (exprs *exprParams) addParam(colName string, arg interface{}) {
|
||||
exprs.colNames = append(exprs.colNames, colName)
|
||||
exprs.args = append(exprs.args, arg)
|
||||
}
|
||||
|
||||
func (exprs *exprParams) isColExist(colName string) bool {
|
||||
for _, name := range exprs.colNames {
|
||||
if strings.EqualFold(trimQuote(name), trimQuote(colName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (exprs *exprParams) getByName(colName string) (exprParam, bool) {
|
||||
for i, name := range exprs.colNames {
|
||||
if strings.EqualFold(name, colName) {
|
||||
return exprParam{name, exprs.args[i]}, true
|
||||
}
|
||||
}
|
||||
return exprParam{}, false
|
||||
}
|
||||
|
||||
func (exprs *exprParams) writeArgs(w *builder.BytesWriter) error {
|
||||
for i, expr := range exprs.args {
|
||||
switch arg := expr.(type) {
|
||||
case *builder.Builder:
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := arg.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(")"); err != nil {
|
||||
return err
|
||||
}
|
||||
case string:
|
||||
if arg == "" {
|
||||
arg = "''"
|
||||
}
|
||||
if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if _, err := w.WriteString("?"); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Append(arg)
|
||||
}
|
||||
if i != len(exprs.args)-1 {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (exprs *exprParams) writeNameArgs(w *builder.BytesWriter) error {
|
||||
for i, colName := range exprs.colNames {
|
||||
if _, err := w.WriteString(colName); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString("="); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch arg := exprs.args[i].(type) {
|
||||
case *builder.Builder:
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := arg.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString("("); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
w.Append(exprs.args[i])
|
||||
}
|
||||
|
||||
if i+1 != len(exprs.colNames) {
|
||||
if _, err := w.WriteString(","); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
func trimQuote(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
if s[0] == '`' {
|
||||
s = s[1:]
|
||||
}
|
||||
if len(s) > 0 && s[len(s)-1] == '`' {
|
||||
return s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !windows && !nacl && !plan9
|
||||
// +build !windows,!nacl,!plan9
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/syslog"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
var _ core.ILogger = &SyslogLogger{}
|
||||
|
||||
// SyslogLogger will be depricated
|
||||
type SyslogLogger struct {
|
||||
w *syslog.Writer
|
||||
showSQL bool
|
||||
}
|
||||
|
||||
// NewSyslogLogger implements core.ILogger
|
||||
func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
|
||||
return &SyslogLogger{w: w}
|
||||
}
|
||||
|
||||
// Debug log content as Debug
|
||||
func (s *SyslogLogger) Debug(v ...interface{}) {
|
||||
s.w.Debug(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Debugf log content as Debug and format
|
||||
func (s *SyslogLogger) Debugf(format string, v ...interface{}) {
|
||||
s.w.Debug(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Error log content as Error
|
||||
func (s *SyslogLogger) Error(v ...interface{}) {
|
||||
s.w.Err(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Errorf log content as Errorf and format
|
||||
func (s *SyslogLogger) Errorf(format string, v ...interface{}) {
|
||||
s.w.Err(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Info log content as Info
|
||||
func (s *SyslogLogger) Info(v ...interface{}) {
|
||||
s.w.Info(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Infof log content as Infof and format
|
||||
func (s *SyslogLogger) Infof(format string, v ...interface{}) {
|
||||
s.w.Info(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Warn log content as Warn
|
||||
func (s *SyslogLogger) Warn(v ...interface{}) {
|
||||
s.w.Warning(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Warnf log content as Warnf and format
|
||||
func (s *SyslogLogger) Warnf(format string, v ...interface{}) {
|
||||
s.w.Warning(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Level shows log level
|
||||
func (s *SyslogLogger) Level() core.LogLevel {
|
||||
return core.LOG_UNKNOWN
|
||||
}
|
||||
|
||||
// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
|
||||
func (s *SyslogLogger) SetLevel(l core.LogLevel) {}
|
||||
|
||||
// ShowSQL set if logging SQL
|
||||
func (s *SyslogLogger) ShowSQL(show ...bool) {
|
||||
if len(show) == 0 {
|
||||
s.showSQL = true
|
||||
return
|
||||
}
|
||||
s.showSQL = show[0]
|
||||
}
|
||||
|
||||
// IsShowSQL if logging SQL
|
||||
func (s *SyslogLogger) IsShowSQL() bool {
|
||||
return s.showSQL
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2020 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
func getTableName(mapper core.IMapper, v reflect.Value) string {
|
||||
if t, ok := v.Interface().(TableName); ok {
|
||||
return t.TableName()
|
||||
}
|
||||
if v.Type().Implements(tpTableName) {
|
||||
return v.Interface().(TableName).TableName()
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
if t, ok := v.Interface().(TableName); ok {
|
||||
return t.TableName()
|
||||
}
|
||||
if v.Type().Implements(tpTableName) {
|
||||
return v.Interface().(TableName).TableName()
|
||||
}
|
||||
}
|
||||
|
||||
return mapper.Obj2Table(v.Type().Name())
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
type tagContext struct {
|
||||
tagName string
|
||||
params []string
|
||||
preTag, nextTag string
|
||||
table *core.Table
|
||||
col *core.Column
|
||||
fieldValue reflect.Value
|
||||
isIndex bool
|
||||
isUnique bool
|
||||
indexNames map[string]int
|
||||
engine *Engine
|
||||
ignoreNext bool
|
||||
}
|
||||
|
||||
// tagHandler describes tag handler for XORM
|
||||
type tagHandler func(ctx *tagContext) error
|
||||
|
||||
var (
|
||||
// defaultTagHandlers enumerates all the default tag handler
|
||||
defaultTagHandlers = map[string]tagHandler{
|
||||
"<-": OnlyFromDBTagHandler,
|
||||
"->": OnlyToDBTagHandler,
|
||||
"PK": PKTagHandler,
|
||||
"NULL": NULLTagHandler,
|
||||
"NOT": IgnoreTagHandler,
|
||||
"AUTOINCR": AutoIncrTagHandler,
|
||||
"DEFAULT": DefaultTagHandler,
|
||||
"CREATED": CreatedTagHandler,
|
||||
"UPDATED": UpdatedTagHandler,
|
||||
"DELETED": DeletedTagHandler,
|
||||
"VERSION": VersionTagHandler,
|
||||
"UTC": UTCTagHandler,
|
||||
"LOCAL": LocalTagHandler,
|
||||
"NOTNULL": NotNullTagHandler,
|
||||
"INDEX": IndexTagHandler,
|
||||
"UNIQUE": UniqueTagHandler,
|
||||
"COMMENT": CommentTagHandler,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
for k := range core.SqlTypes {
|
||||
defaultTagHandlers[k] = SQLTypeTagHandler
|
||||
}
|
||||
}
|
||||
|
||||
// IgnoreTagHandler describes ignored tag handler
|
||||
func IgnoreTagHandler(ctx *tagContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnlyFromDBTagHandler describes mapping direction tag handler
|
||||
func OnlyFromDBTagHandler(ctx *tagContext) error {
|
||||
ctx.col.MapType = core.ONLYFROMDB
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnlyToDBTagHandler describes mapping direction tag handler
|
||||
func OnlyToDBTagHandler(ctx *tagContext) error {
|
||||
ctx.col.MapType = core.ONLYTODB
|
||||
return nil
|
||||
}
|
||||
|
||||
// PKTagHandler describes primary key tag handler
|
||||
func PKTagHandler(ctx *tagContext) error {
|
||||
ctx.col.IsPrimaryKey = true
|
||||
ctx.col.Nullable = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// NULLTagHandler describes null tag handler
|
||||
func NULLTagHandler(ctx *tagContext) error {
|
||||
ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotNullTagHandler describes notnull tag handler
|
||||
func NotNullTagHandler(ctx *tagContext) error {
|
||||
ctx.col.Nullable = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// AutoIncrTagHandler describes autoincr tag handler
|
||||
func AutoIncrTagHandler(ctx *tagContext) error {
|
||||
ctx.col.IsAutoIncrement = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultTagHandler describes default tag handler
|
||||
func DefaultTagHandler(ctx *tagContext) error {
|
||||
if len(ctx.params) > 0 {
|
||||
ctx.col.Default = ctx.params[0]
|
||||
} else {
|
||||
ctx.col.Default = ctx.nextTag
|
||||
ctx.ignoreNext = true
|
||||
}
|
||||
ctx.col.DefaultIsEmpty = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreatedTagHandler describes created tag handler
|
||||
func CreatedTagHandler(ctx *tagContext) error {
|
||||
ctx.col.IsCreated = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// VersionTagHandler describes version tag handler
|
||||
func VersionTagHandler(ctx *tagContext) error {
|
||||
ctx.col.IsVersion = true
|
||||
ctx.col.Default = "1"
|
||||
return nil
|
||||
}
|
||||
|
||||
// UTCTagHandler describes utc tag handler
|
||||
func UTCTagHandler(ctx *tagContext) error {
|
||||
ctx.col.TimeZone = time.UTC
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalTagHandler describes local tag handler
|
||||
func LocalTagHandler(ctx *tagContext) error {
|
||||
if len(ctx.params) == 0 {
|
||||
ctx.col.TimeZone = time.Local
|
||||
} else {
|
||||
var err error
|
||||
ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatedTagHandler describes updated tag handler
|
||||
func UpdatedTagHandler(ctx *tagContext) error {
|
||||
ctx.col.IsUpdated = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletedTagHandler describes deleted tag handler
|
||||
func DeletedTagHandler(ctx *tagContext) error {
|
||||
ctx.col.IsDeleted = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// IndexTagHandler describes index tag handler
|
||||
func IndexTagHandler(ctx *tagContext) error {
|
||||
if len(ctx.params) > 0 {
|
||||
ctx.indexNames[ctx.params[0]] = core.IndexType
|
||||
} else {
|
||||
ctx.isIndex = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UniqueTagHandler describes unique tag handler
|
||||
func UniqueTagHandler(ctx *tagContext) error {
|
||||
if len(ctx.params) > 0 {
|
||||
ctx.indexNames[ctx.params[0]] = core.UniqueType
|
||||
} else {
|
||||
ctx.isUnique = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommentTagHandler add comment to column
|
||||
func CommentTagHandler(ctx *tagContext) error {
|
||||
if len(ctx.params) > 0 {
|
||||
ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SQLTypeTagHandler describes SQL Type tag handler
|
||||
func SQLTypeTagHandler(ctx *tagContext) error {
|
||||
ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
|
||||
if len(ctx.params) > 0 {
|
||||
if ctx.tagName == core.Enum {
|
||||
ctx.col.EnumOptions = make(map[string]int)
|
||||
for k, v := range ctx.params {
|
||||
v = strings.TrimSpace(v)
|
||||
v = strings.Trim(v, "'")
|
||||
ctx.col.EnumOptions[v] = k
|
||||
}
|
||||
} else if ctx.tagName == core.Set {
|
||||
ctx.col.SetOptions = make(map[string]int)
|
||||
for k, v := range ctx.params {
|
||||
v = strings.TrimSpace(v)
|
||||
v = strings.Trim(v, "'")
|
||||
ctx.col.SetOptions[v] = k
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
if len(ctx.params) == 2 {
|
||||
ctx.col.Length, err = strconv.Atoi(ctx.params[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(ctx.params) == 1 {
|
||||
ctx.col.Length, err = strconv.Atoi(ctx.params[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtendsTagHandler describes extends tag handler
|
||||
func ExtendsTagHandler(ctx *tagContext) error {
|
||||
var fieldValue = ctx.fieldValue
|
||||
var isPtr = false
|
||||
switch fieldValue.Kind() {
|
||||
case reflect.Ptr:
|
||||
f := fieldValue.Type().Elem()
|
||||
if f.Kind() == reflect.Struct {
|
||||
fieldPtr := fieldValue
|
||||
fieldValue = fieldValue.Elem()
|
||||
if !fieldValue.IsValid() || fieldPtr.IsNil() {
|
||||
fieldValue = reflect.New(f).Elem()
|
||||
}
|
||||
}
|
||||
isPtr = true
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
parentTable, err := ctx.engine.mapType(fieldValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, col := range parentTable.Columns() {
|
||||
col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
|
||||
|
||||
var tagPrefix = ctx.col.FieldName
|
||||
if len(ctx.params) > 0 {
|
||||
col.Nullable = isPtr
|
||||
tagPrefix = ctx.params[0]
|
||||
if col.IsPrimaryKey {
|
||||
col.Name = ctx.col.FieldName
|
||||
col.IsPrimaryKey = false
|
||||
} else {
|
||||
col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if col.Nullable {
|
||||
col.IsAutoIncrement = false
|
||||
col.IsPrimaryKey = false
|
||||
}
|
||||
|
||||
ctx.table.AddColumn(col)
|
||||
for indexName, indexType := range col.Indexes {
|
||||
addIndex(indexName, ctx.table, col, indexType)
|
||||
}
|
||||
}
|
||||
default:
|
||||
//TODO: warning
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
// Copyright 2015 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.8
|
||||
// +build go1.8
|
||||
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version show the xorm's version
|
||||
Version string = "0.8.0.1015"
|
||||
)
|
||||
|
||||
func regDrvsNDialects() bool {
|
||||
providedDrvsNDialects := map[string]struct {
|
||||
dbType core.DbType
|
||||
getDriver func() core.Driver
|
||||
getDialect func() core.Dialect
|
||||
}{
|
||||
"mysql": {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
|
||||
"mymysql": {"mysql", func() core.Driver { return &mymysqlDriver{} }, func() core.Dialect { return &mysql{} }},
|
||||
"postgres": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
|
||||
"pgx": {"postgres", func() core.Driver { return &pqDriverPgx{} }, func() core.Dialect { return &postgres{} }},
|
||||
"sqlite3": {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }},
|
||||
}
|
||||
|
||||
for driverName, v := range providedDrvsNDialects {
|
||||
if driver := core.QueryDriver(driverName); driver == nil {
|
||||
core.RegisterDriver(driverName, v.getDriver())
|
||||
core.RegisterDialect(v.dbType, v.getDialect)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func close(engine *Engine) {
|
||||
engine.Close()
|
||||
}
|
||||
|
||||
func init() {
|
||||
regDrvsNDialects()
|
||||
}
|
||||
|
||||
// NewEngine new a db manager according to the parameter. Currently support four
|
||||
// drivers
|
||||
func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||
driver := core.QueryDriver(driverName)
|
||||
if driver == nil {
|
||||
return nil, fmt.Errorf("unsupported driver name: %v", driverName)
|
||||
}
|
||||
|
||||
uri, err := driver.Parse(driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dialect := core.QueryDialect(uri.DbType)
|
||||
if dialect == nil {
|
||||
return nil, fmt.Errorf("unsupported dialect type: %v", uri.DbType)
|
||||
}
|
||||
|
||||
db, err := core.Open(driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dialect.Init(db, uri, driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
engine := &Engine{
|
||||
db: db,
|
||||
dialect: dialect,
|
||||
Tables: make(map[reflect.Type]*core.Table),
|
||||
mutex: &sync.RWMutex{},
|
||||
TagIdentifier: "xorm",
|
||||
TZLocation: time.Local,
|
||||
tagHandlers: defaultTagHandlers,
|
||||
defaultContext: context.Background(),
|
||||
}
|
||||
|
||||
if uri.DbType == core.SQLITE {
|
||||
engine.DatabaseTZ = time.UTC
|
||||
} else {
|
||||
engine.DatabaseTZ = time.Local
|
||||
}
|
||||
|
||||
logger := NewSimpleLogger(os.Stdout)
|
||||
logger.SetLevel(core.LOG_INFO)
|
||||
engine.SetLogger(logger)
|
||||
engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
|
||||
|
||||
runtime.SetFinalizer(engine, close)
|
||||
|
||||
return engine, nil
|
||||
}
|
||||
Reference in New Issue
Block a user